Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 22:48:14 +0000 (15:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 22:48:14 +0000 (15:48 -0700)
Pull ARM SoC platform updates from Arnd Bergmann:
 "The main change this time around is a cleanup of some of the oldest
  platforms based on the XScale and ARM9 CPU cores, which are between 10
  and 20 years old.

  The Kendin/Micrel/Microchip KS8695, Winbond/Nuvoton W90x900 and Intel
  IOP33x/IOP13xx platforms are removed after we determined that nobody
  is using them any more.

  The TI Davinci and NXP LPC32xx platforms on the other hand are still
  in active use and are converted to the ARCH_MULTIPLATFORM build,
  meaning that we can compile a kernel that works on these along with
  most other ARMv5 platforms. Changes toward that goal are also merged
  for IOP32x, but additional work is needed to complete this. Patches
  for the remaining ARMv5 platforms have started but need more work and
  some testing.

  Support for the new ASpeed AST2600 gets added, this is based on the
  Cortex-A7 ARMv7 core, and is a newer version of the existing ARMv5 and
  ARMv6 chips in the same family.

  Other changes include a cleanup of the ST-Ericsson ux500 platform and
  the move of the TI Davinci platform to a new clocksource driver"

[ The changes had marked INTEL_IOP_ADMA and USB_LPC32XX as being
  buildable on other platforms through COMPILE_TEST, but that causes new
  warnings that I most definitely do not want to see during the merge
  window as that could hide other issues.

  So the COMPILE_TEST option got disabled for them again   - Linus ]

* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (61 commits)
  ARM: multi_v5_defconfig: make DaVinci part of the ARM v5 multiplatform build
  ARM: davinci: support multiplatform build for ARM v5
  arm64: exynos: Enable exynos-chipid driver
  ARM: OMAP2+: Delete an unnecessary kfree() call in omap_hsmmc_pdata_init()
  ARM: OMAP2+: move platform-specific asm-offset.h to arch/arm/mach-omap2
  ARM: davinci: dm646x: Fix a typo in the comment
  ARM: davinci: dm646x: switch to using the clocksource driver
  ARM: davinci: dm644x: switch to using the clocksource driver
  ARM: aspeed: Enable SMP boot
  ARM: aspeed: Add ASPEED AST2600 architecture
  ARM: aspeed: Select timer in each SoC
  dt-bindings: arm: cpus: Add ASPEED SMP
  ARM: imx: stop adjusting ar8031 phy tx delay
  mailmap: map old company name to new one @microchip.com
  MAINTAINERS: at91: remove the TC entry
  MAINTAINERS: at91: Collect all pinctrl/gpio drivers in same entry
  ARM: at91: move platform-specific asm-offset.h to arch/arm/mach-at91
  MAINTAINERS: Extend patterns for Samsung SoC, Security Subsystem and clock drivers
  ARM: s3c64xx: squash samsung_usb_phy.h into setup-usb-phy.c
  ARM: debug-ll: Add support for r7s9210
  ...

1631 files changed:
.clang-format
.mailmap
Documentation/PCI/index.rst
Documentation/PCI/pciebus-howto.rst [new file with mode: 0644]
Documentation/PCI/picebus-howto.rst [deleted file]
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/perf/imx-ddr.rst [new file with mode: 0644]
Documentation/admin-guide/sysctl/net.rst
Documentation/arm64/index.rst
Documentation/arm64/kasan-offsets.sh [new file with mode: 0644]
Documentation/arm64/memory.rst
Documentation/arm64/tagged-address-abi.rst [new file with mode: 0644]
Documentation/arm64/tagged-pointers.rst
Documentation/devicetree/bindings/Makefile
Documentation/devicetree/bindings/arm/topology.txt [deleted file]
Documentation/devicetree/bindings/cpu/cpu-topology.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
Documentation/devicetree/bindings/gpio/gpio-davinci.txt
Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ads1015.txt [deleted file]
Documentation/devicetree/bindings/hwmon/as370.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
Documentation/devicetree/bindings/hwmon/lm75.txt
Documentation/devicetree/bindings/iio/adc/ads1015.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt
Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
Documentation/devicetree/bindings/net/dsa/ksz.txt
Documentation/devicetree/bindings/net/fsl-fec.txt
Documentation/devicetree/bindings/net/macb.txt
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/regulator/act8865-regulator.txt
Documentation/devicetree/bindings/regulator/fixed-regulator.yaml
Documentation/devicetree/bindings/regulator/mt6358-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
Documentation/devicetree/bindings/regulator/sy8824x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/twl-regulator.txt
Documentation/devicetree/bindings/regulator/uniphier-regulator.txt
Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt
Documentation/devicetree/bindings/spi/spi-mt65xx.txt
Documentation/devicetree/bindings/spi/spi-sprd-adi.txt
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/sgi-ioc4.rst [deleted file]
Documentation/features/core/jump-labels/arch-support.txt
Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
Documentation/hwmon/ads1015.rst [deleted file]
Documentation/hwmon/index.rst
Documentation/hwmon/inspur-ipsps1.rst [new file with mode: 0644]
Documentation/hwmon/lm75.rst
Documentation/hwmon/pxe1610 [deleted file]
Documentation/hwmon/pxe1610.rst [new file with mode: 0644]
Documentation/hwmon/shtc1.rst
Documentation/hwmon/submitting-patches.rst
Documentation/networking/tls-offload.rst
Documentation/networking/tuntap.txt
Documentation/process/embargoed-hardware-issues.rst [new file with mode: 0644]
Documentation/process/index.rst
Documentation/riscv/boot-image-header.txt
Documentation/security/tpm/index.rst
Documentation/security/tpm/tpm_ftpm_tee.rst [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig
arch/arc/boot/dts/Makefile
arch/arc/include/asm/entry-arcv2.h
arch/arc/include/asm/linkage.h
arch/arc/include/asm/mach_desc.h
arch/arc/kernel/mcip.c
arch/arc/kernel/unwind.c
arch/arc/mm/dma.c
arch/arc/plat-hsdk/platform.c
arch/arm/Kconfig
arch/arm/boot/dts/am33xx-l4.dtsi
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am437x-l4.dtsi
arch/arm/boot/dts/am571x-idk.dts
arch/arm/boot/dts/am572x-idk.dts
arch/arm/boot/dts/am574x-idk.dts
arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
arch/arm/boot/dts/am57xx-beagle-x15-revb1.dts
arch/arm/boot/dts/am57xx-beagle-x15-revc.dts
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7-l4.dtsi
arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi
arch/arm/boot/dts/vf610-bk4.dts
arch/arm/include/asm/topology.h
arch/arm/kernel/topology.c
arch/arm/lib/backtrace.S
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-omap1/ams-delta-fiq-handler.S
arch/arm/mach-omap1/ams-delta-fiq.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/omap-iommu.c [new file with mode: 0644]
arch/arm/mach-omap2/omap4-common.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mm/Kconfig
arch/arm/mm/dma-mapping.c
arch/arm/mm/init.c
arch/arm64/Kbuild [new file with mode: 0644]
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts
arch/arm64/boot/dts/renesas/hihope-common.dtsi
arch/arm64/boot/dts/renesas/r8a77995-draak.dts
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/atomic.h
arch/arm64/include/asm/atomic_ll_sc.h
arch/arm64/include/asm/atomic_lse.h
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/cpu_ops.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/debug-monitors.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/exception.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/futex.h
arch/arm64/include/asm/hw_breakpoint.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/irqflags.h
arch/arm64/include/asm/kasan.h
arch/arm64/include/asm/lse.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pci.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/pointer_auth.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/signal32.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/tlbflush.h
arch/arm64/include/asm/topology.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/vdso.h
arch/arm64/include/asm/vdso_datapage.h
arch/arm64/include/uapi/asm/stat.h [deleted file]
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuidle.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hibernate-asm.S
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/image-vars.h [new file with mode: 0644]
arch/arm64/kernel/image.h
arch/arm64/kernel/insn.c
arch/arm64/kernel/kaslr.c
arch/arm64/kernel/kexec_image.c
arch/arm64/kernel/machine_kexec_file.c
arch/arm64/kernel/module-plts.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/process.c
arch/arm64/kernel/psci.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/smp_spin_table.c
arch/arm64/kernel/topology.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/va_layout.c
arch/arm64/lib/Makefile
arch/arm64/lib/atomic_ll_sc.c [deleted file]
arch/arm64/lib/error-inject.c [new file with mode: 0644]
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/dump.c
arch/arm64/mm/fault.c
arch/arm64/mm/init.c
arch/arm64/mm/ioremap.c
arch/arm64/mm/kasan_init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/numa.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/proc.S
arch/ia64/Kconfig
arch/ia64/Kconfig.debug
arch/ia64/Makefile
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/sim_defconfig [deleted file]
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/dig/Makefile [deleted file]
arch/ia64/dig/machvec.c [deleted file]
arch/ia64/dig/machvec_vtd.c [deleted file]
arch/ia64/dig/setup.c [deleted file]
arch/ia64/hp/common/Makefile
arch/ia64/hp/common/hwsw_iommu.c [deleted file]
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/Kconfig [deleted file]
arch/ia64/hp/sim/Makefile [deleted file]
arch/ia64/hp/sim/boot/Makefile [deleted file]
arch/ia64/hp/sim/boot/boot_head.S [deleted file]
arch/ia64/hp/sim/boot/bootloader.c [deleted file]
arch/ia64/hp/sim/boot/bootloader.lds [deleted file]
arch/ia64/hp/sim/boot/fw-emu.c [deleted file]
arch/ia64/hp/sim/boot/ssc.h [deleted file]
arch/ia64/hp/sim/hpsim.S [deleted file]
arch/ia64/hp/sim/hpsim_console.c [deleted file]
arch/ia64/hp/sim/hpsim_irq.c [deleted file]
arch/ia64/hp/sim/hpsim_machvec.c [deleted file]
arch/ia64/hp/sim/hpsim_setup.c [deleted file]
arch/ia64/hp/sim/hpsim_ssc.h [deleted file]
arch/ia64/hp/sim/simeth.c [deleted file]
arch/ia64/hp/sim/simscsi.c [deleted file]
arch/ia64/hp/sim/simserial.c [deleted file]
arch/ia64/hp/zx1/Makefile [deleted file]
arch/ia64/hp/zx1/hpzx1_machvec.c [deleted file]
arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c [deleted file]
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/dma-mapping.h
arch/ia64/include/asm/dma.h
arch/ia64/include/asm/hpsim.h [deleted file]
arch/ia64/include/asm/hw_irq.h
arch/ia64/include/asm/io.h
arch/ia64/include/asm/iommu.h
arch/ia64/include/asm/iosapic.h
arch/ia64/include/asm/irq.h
arch/ia64/include/asm/machvec.h [deleted file]
arch/ia64/include/asm/machvec_dig.h [deleted file]
arch/ia64/include/asm/machvec_dig_vtd.h [deleted file]
arch/ia64/include/asm/machvec_hpsim.h [deleted file]
arch/ia64/include/asm/machvec_hpzx1.h [deleted file]
arch/ia64/include/asm/machvec_hpzx1_swiotlb.h [deleted file]
arch/ia64/include/asm/machvec_init.h [deleted file]
arch/ia64/include/asm/machvec_sn2.h [deleted file]
arch/ia64/include/asm/machvec_uv.h [deleted file]
arch/ia64/include/asm/mmiowb.h
arch/ia64/include/asm/mmzone.h
arch/ia64/include/asm/pci.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/sn/acpi.h [deleted file]
arch/ia64/include/asm/sn/addrs.h [deleted file]
arch/ia64/include/asm/sn/arch.h [deleted file]
arch/ia64/include/asm/sn/bte.h [deleted file]
arch/ia64/include/asm/sn/clksupport.h [deleted file]
arch/ia64/include/asm/sn/geo.h [deleted file]
arch/ia64/include/asm/sn/intr.h
arch/ia64/include/asm/sn/io.h [deleted file]
arch/ia64/include/asm/sn/ioc3.h [deleted file]
arch/ia64/include/asm/sn/klconfig.h [deleted file]
arch/ia64/include/asm/sn/l1.h [deleted file]
arch/ia64/include/asm/sn/leds.h [deleted file]
arch/ia64/include/asm/sn/module.h [deleted file]
arch/ia64/include/asm/sn/mspec.h [deleted file]
arch/ia64/include/asm/sn/nodepda.h [deleted file]
arch/ia64/include/asm/sn/pcibr_provider.h [deleted file]
arch/ia64/include/asm/sn/pcibus_provider_defs.h [deleted file]
arch/ia64/include/asm/sn/pcidev.h [deleted file]
arch/ia64/include/asm/sn/pda.h [deleted file]
arch/ia64/include/asm/sn/pic.h [deleted file]
arch/ia64/include/asm/sn/rw_mmr.h [deleted file]
arch/ia64/include/asm/sn/shub_mmr.h [deleted file]
arch/ia64/include/asm/sn/shubio.h [deleted file]
arch/ia64/include/asm/sn/simulator.h [deleted file]
arch/ia64/include/asm/sn/sn2/sn_hwperf.h [deleted file]
arch/ia64/include/asm/sn/sn_cpuid.h [deleted file]
arch/ia64/include/asm/sn/sn_feature_sets.h [deleted file]
arch/ia64/include/asm/sn/sn_sal.h
arch/ia64/include/asm/sn/tioca.h [deleted file]
arch/ia64/include/asm/sn/tioca_provider.h [deleted file]
arch/ia64/include/asm/sn/tioce.h [deleted file]
arch/ia64/include/asm/sn/tioce_provider.h [deleted file]
arch/ia64/include/asm/sn/tiocp.h [deleted file]
arch/ia64/include/asm/sn/tiocx.h [deleted file]
arch/ia64/include/asm/sn/types.h [deleted file]
arch/ia64/include/asm/switch_to.h
arch/ia64/include/asm/tlb.h
arch/ia64/include/asm/uv/uv.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/acpi.c
arch/ia64/kernel/dma-mapping.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/machvec.c [deleted file]
arch/ia64/kernel/mca.c
arch/ia64/kernel/mca_drv.c
arch/ia64/kernel/module.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/pci-dma.c
arch/ia64/kernel/sal.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/signal.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/sys_ia64.c
arch/ia64/kernel/time.c
arch/ia64/kernel/topology.c
arch/ia64/kernel/unaligned.c
arch/ia64/kernel/uncached.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/lib/io.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/mm/tlb.c
arch/ia64/pci/fixup.c
arch/ia64/pci/pci.c
arch/ia64/sn/Makefile [deleted file]
arch/ia64/sn/include/ioerror.h [deleted file]
arch/ia64/sn/include/tio.h [deleted file]
arch/ia64/sn/include/xtalk/hubdev.h [deleted file]
arch/ia64/sn/include/xtalk/xbow.h [deleted file]
arch/ia64/sn/include/xtalk/xwidgetdev.h [deleted file]
arch/ia64/sn/kernel/Makefile [deleted file]
arch/ia64/sn/kernel/bte.c [deleted file]
arch/ia64/sn/kernel/bte_error.c [deleted file]
arch/ia64/sn/kernel/huberror.c [deleted file]
arch/ia64/sn/kernel/idle.c [deleted file]
arch/ia64/sn/kernel/io_acpi_init.c [deleted file]
arch/ia64/sn/kernel/io_common.c [deleted file]
arch/ia64/sn/kernel/io_init.c [deleted file]
arch/ia64/sn/kernel/iomv.c [deleted file]
arch/ia64/sn/kernel/irq.c [deleted file]
arch/ia64/sn/kernel/klconflib.c [deleted file]
arch/ia64/sn/kernel/machvec.c [deleted file]
arch/ia64/sn/kernel/mca.c [deleted file]
arch/ia64/sn/kernel/msi_sn.c [deleted file]
arch/ia64/sn/kernel/pio_phys.S [deleted file]
arch/ia64/sn/kernel/setup.c [deleted file]
arch/ia64/sn/kernel/sn2/Makefile [deleted file]
arch/ia64/sn/kernel/sn2/cache.c [deleted file]
arch/ia64/sn/kernel/sn2/io.c [deleted file]
arch/ia64/sn/kernel/sn2/prominfo_proc.c [deleted file]
arch/ia64/sn/kernel/sn2/ptc_deadlock.S [deleted file]
arch/ia64/sn/kernel/sn2/sn2_smp.c [deleted file]
arch/ia64/sn/kernel/sn2/sn_hwperf.c [deleted file]
arch/ia64/sn/kernel/sn2/sn_proc_fs.c [deleted file]
arch/ia64/sn/kernel/sn2/timer.c [deleted file]
arch/ia64/sn/kernel/sn2/timer_interrupt.c [deleted file]
arch/ia64/sn/kernel/tiocx.c [deleted file]
arch/ia64/sn/pci/Makefile [deleted file]
arch/ia64/sn/pci/pci_dma.c [deleted file]
arch/ia64/sn/pci/pcibr/Makefile [deleted file]
arch/ia64/sn/pci/pcibr/pcibr_ate.c [deleted file]
arch/ia64/sn/pci/pcibr/pcibr_dma.c [deleted file]
arch/ia64/sn/pci/pcibr/pcibr_provider.c [deleted file]
arch/ia64/sn/pci/pcibr/pcibr_reg.c [deleted file]
arch/ia64/sn/pci/tioca_provider.c [deleted file]
arch/ia64/sn/pci/tioce_provider.c [deleted file]
arch/ia64/uv/kernel/Makefile
arch/ia64/uv/kernel/machvec.c [deleted file]
arch/ia64/uv/kernel/setup.c
arch/m68k/atari/config.c
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/atarihw.h
arch/m68k/include/asm/io_mm.h
arch/m68k/include/asm/kmap.h
arch/m68k/include/asm/macintosh.h
arch/m68k/mac/config.c
arch/mips/configs/bigsur_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/markeins_defconfig
arch/mips/configs/rm200_defconfig
arch/mips/configs/sb1250_swarm_defconfig
arch/mips/include/asm/octeon/cvmx-sli-defs.h
arch/nds32/kernel/signal.c
arch/parisc/Kconfig
arch/parisc/boot/compressed/.gitignore
arch/parisc/include/asm/alternative.h
arch/parisc/include/asm/fixmap.h
arch/parisc/include/asm/ftrace.h
arch/parisc/include/asm/kexec.h [new file with mode: 0644]
arch/parisc/include/asm/pdc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/string.h
arch/parisc/kernel/Makefile
arch/parisc/kernel/alternative.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/ftrace.c
arch/parisc/kernel/kexec.c [new file with mode: 0644]
arch/parisc/kernel/kexec_file.c [new file with mode: 0644]
arch/parisc/kernel/kprobes.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/relocate_kernel.S [new file with mode: 0644]
arch/parisc/kernel/smp.c
arch/parisc/kernel/syscalls/syscall.tbl
arch/parisc/kernel/traps.c
arch/parisc/lib/Makefile
arch/parisc/lib/memset.c [deleted file]
arch/parisc/lib/string.S [new file with mode: 0644]
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/include/asm/error-injection.h [deleted file]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/dma-common.c [deleted file]
arch/powerpc/kernel/kexec_elf_64.c
arch/powerpc/kernel/process.c
arch/powerpc/kvm/book3s_64_vio.c
arch/powerpc/kvm/book3s_64_vio_hv.c
arch/powerpc/mm/nohash/tlb.c
arch/riscv/Kbuild [new file with mode: 0644]
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/configs/defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/fixmap.h
arch/riscv/include/asm/image.h
arch/riscv/include/asm/page.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/smp.h
arch/riscv/include/asm/sparsemem.h [new file with mode: 0644]
arch/riscv/include/asm/switch_to.h
arch/riscv/include/asm/timex.h
arch/riscv/include/asm/tlbflush.h
arch/riscv/include/uapi/asm/perf_regs.h [new file with mode: 0644]
arch/riscv/kernel/Makefile
arch/riscv/kernel/entry.S
arch/riscv/kernel/fpu.S
arch/riscv/kernel/head.S
arch/riscv/kernel/perf_callchain.c [new file with mode: 0644]
arch/riscv/kernel/perf_regs.c [new file with mode: 0644]
arch/riscv/kernel/process.c
arch/riscv/kernel/smp.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/stacktrace.c
arch/riscv/lib/uaccess.S
arch/riscv/mm/Makefile
arch/riscv/mm/cacheflush.c
arch/riscv/mm/context.c
arch/riscv/mm/init.c
arch/riscv/mm/tlbflush.c [new file with mode: 0644]
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/net/bpf_jit_comp.c
arch/sh/kernel/disassemble.c
arch/sh/kernel/hw_breakpoint.c
arch/sparc/kernel/sys_sparc_64.c
arch/um/include/shared/timer-internal.h
arch/um/kernel/process.c
arch/um/kernel/time.c
arch/unicore32/kernel/irq.c
arch/x86/Makefile
arch/x86/boot/compressed/pgtable_64.c
arch/x86/events/amd/ibs.c
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/hyperv/mmu.c
arch/x86/include/asm/bootparam_utils.h
arch/x86/include/asm/error-injection.h [deleted file]
arch/x86/include/asm/ftrace.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/iommu.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/uaccess.h
arch/x86/kernel/amd_nb.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/mce/severity.c
arch/x86/kernel/cpu/umwait.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/uprobes.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/math-emu/errors.c
arch/x86/math-emu/fpu_trig.c
arch/x86/mm/pageattr.c
arch/x86/net/bpf_jit_comp.c
arch/x86/power/cpu.c
arch/x86/purgatory/Makefile
arch/xtensa/kernel/setup.c
block/blk-mq.c
block/blk-sysfs.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/arm64/iort.c
drivers/acpi/pptt.c
drivers/atm/Kconfig
drivers/auxdisplay/Kconfig
drivers/auxdisplay/charlcd.c
drivers/auxdisplay/charlcd.h [new file with mode: 0644]
drivers/auxdisplay/hd44780.c
drivers/auxdisplay/ht16k33.c
drivers/auxdisplay/panel.c
drivers/base/Kconfig
drivers/base/arch_topology.c
drivers/base/regmap/Kconfig
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/block/drbd/drbd_main.c
drivers/block/rbd.c
drivers/block/xen-blkback/xenbus.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/btqca.c
drivers/bluetooth/btqca.h
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_qca.c
drivers/bus/hisi_lpc.c
drivers/bus/ti-sysc.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/Kconfig
drivers/char/agp/Makefile
drivers/char/agp/sgi-agp.c [deleted file]
drivers/char/mbcs.c [deleted file]
drivers/char/mbcs.h [deleted file]
drivers/char/mspec.c
drivers/char/random.c
drivers/char/snsc.c [deleted file]
drivers/char/snsc.h [deleted file]
drivers/char/snsc_event.c [deleted file]
drivers/char/tpm/Kconfig
drivers/char/tpm/Makefile
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm_ftpm_tee.c [new file with mode: 0644]
drivers/char/tpm/tpm_ftpm_tee.h [new file with mode: 0644]
drivers/char/tpm/tpm_tis_core.c
drivers/clk/clk.c
drivers/clk/samsung/clk-exynos5-subcmu.c
drivers/clk/samsung/clk-exynos5-subcmu.h
drivers/clk/samsung/clk-exynos5250.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/socfpga/clk-periph-s10.c
drivers/clocksource/timer-riscv.c
drivers/cpufreq/cpufreq.c
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-arm.c
drivers/cpuidle/cpuidle-psci.c [new file with mode: 0644]
drivers/crypto/ccp/ccp-dev.c
drivers/dma/Kconfig
drivers/dma/bcm2835-dma.c
drivers/dma/dw-edma/dw-edma-core.h
drivers/dma/dw-edma/dw-edma-pcie.c
drivers/dma/dw-edma/dw-edma-v0-core.c
drivers/dma/dw-edma/dw-edma-v0-debugfs.c
drivers/dma/fsldma.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/sprd-dma.c
drivers/dma/ste_dma40.c
drivers/dma/stm32-mdma.c
drivers/dma/tegra210-adma.c
drivers/dma/ti/dma-crossbar.c
drivers/dma/ti/omap-dma.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/altera_edac.c
drivers/edac/altera_edac.h
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/bluefield_edac.c [new file with mode: 0644]
drivers/edac/edac_mc.c
drivers/edac/edac_mc.h
drivers/edac/edac_mc_sysfs.c
drivers/edac/ghes_edac.c
drivers/edac/i5100_edac.c
drivers/edac/pnd2_edac.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/psci/psci.c
drivers/firmware/psci/psci_checker.c
drivers/fpga/altera-ps-spi.c
drivers/fsi/fsi-scom.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-bd70528.c
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-cadence.c
drivers/gpio/gpio-creg-snps.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-eic-sprd.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-grgpio.c
drivers/gpio/gpio-hlwd.c
drivers/gpio/gpio-htc-egpio.c
drivers/gpio/gpio-intel-mid.c
drivers/gpio/gpio-ixp4xx.c
drivers/gpio/gpio-ks8695.c [deleted file]
drivers/gpio/gpio-lynxpoint.c
drivers/gpio/gpio-madera.c
drivers/gpio/gpio-max77620.c
drivers/gpio/gpio-max77650.c
drivers/gpio/gpio-mb86s7x.c
drivers/gpio/gpio-merrifield.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-pmic-eic-sprd.c
drivers/gpio/gpio-sprd.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-thunderx.c
drivers/gpio/gpio-tqmx86.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-viperboard.c
drivers/gpio/gpio-xgene-sb.c
drivers/gpio/gpio-xlp.c
drivers/gpio/gpio-zx.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-acpi.h [new file with mode: 0644]
drivers/gpio/gpiolib-devres.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-of.h [new file with mode: 0644]
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpio/sgpio-aspeed.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/nv.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/vega20_ppt.c
drivers/gpu/drm/arm/display/komeda/komeda_dev.c
drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
drivers/gpu/drm/arm/display/komeda/komeda_kms.c
drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_post.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/display/intel_vdsc.c
drivers/gpu/drm/i915/gem/i915_gem_userptr.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_vgpu.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/ingenic/ingenic-drm.c
drivers/gpu/drm/lima/lima_gem.c
drivers/gpu/drm/mediatek/mtk_drm_drv.c
drivers/gpu/drm/mediatek/mtk_drm_drv.h
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp102.c
drivers/gpu/drm/omapdrm/dss/output.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/qxl/qxl_drv.c
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/scheduler/sched_entity.c
drivers/gpu/drm/selftests/drm_cmdline_selftests.h
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/intel-ish-hid/ipc/hw-ish.h
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/wacom_wac.c
drivers/hv/channel.c
drivers/hv/hv_trace.h
drivers/hv/hyperv_vmbus.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/ads1015.c [deleted file]
drivers/hwmon/adt7475.c
drivers/hwmon/as370-hwmon.c [new file with mode: 0644]
drivers/hwmon/asb100.c
drivers/hwmon/coretemp.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm75.c
drivers/hwmon/ltc2990.c
drivers/hwmon/nct6775.c
drivers/hwmon/nct7904.c
drivers/hwmon/npcm750-pwm-fan.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/ibm-cffps.c
drivers/hwmon/pmbus/inspur-ipsps.c [new file with mode: 0644]
drivers/hwmon/pmbus/max31785.c
drivers/hwmon/pmbus/ucd9000.c
drivers/hwmon/raspberrypi-hwmon.c
drivers/hwmon/shtc1.c
drivers/hwmon/smm665.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwtracing/intel_th/msu.h
drivers/hwtracing/intel_th/pci.c
drivers/hwtracing/intel_th/pti.h
drivers/hwtracing/stm/core.c
drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/i2c-designware-slave.c
drivers/i2c/busses/i2c-emev2.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mt65xx.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-stm32.h
drivers/i2c/i2c-core-base.c
drivers/i3c/device.c
drivers/i3c/master.c
drivers/i3c/master/dw-i3c-master.c
drivers/i3c/master/i3c-master-cdns.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/sgiioc4.c [deleted file]
drivers/iio/adc/Kconfig
drivers/iio/adc/max9611.c
drivers/iio/frequency/adf4371.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/counters.c
drivers/infiniband/core/nldev.c
drivers/infiniband/core/restrack.c
drivers/infiniband/core/umem.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
drivers/infiniband/hw/hfi1/fault.c
drivers/infiniband/hw/hfi1/tid_rdma.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx5/devx.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mem.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/odp.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/sw/siw/Kconfig
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_cm.c
drivers/infiniband/sw/siw/siw_cq.c
drivers/infiniband/sw/siw/siw_main.c
drivers/infiniband/sw/siw/siw_mem.c
drivers/infiniband/sw/siw/siw_mem.h
drivers/infiniband/sw/siw/siw_qp.c
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_qp_tx.c
drivers/infiniband/sw/siw/siw_verbs.c
drivers/input/serio/hyperv-keyboard.c
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu.h [new file with mode: 0644]
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_quirks.c [new file with mode: 0644]
drivers/iommu/amd_iommu_types.h
drivers/iommu/arm-smmu-impl.c [new file with mode: 0644]
drivers/iommu/arm-smmu-regs.h [deleted file]
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/arm-smmu.h [new file with mode: 0644]
drivers/iommu/dma-iommu.c
drivers/iommu/dmar.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu-debugfs.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-svm.c
drivers/iommu/intel-trace.c [new file with mode: 0644]
drivers/iommu/intel_irq_remapping.c
drivers/iommu/io-pgtable-arm-v7s.c
drivers/iommu/io-pgtable-arm.c
drivers/iommu/iommu.c
drivers/iommu/iova.c
drivers/iommu/ipmmu-vmsa.c
drivers/iommu/msm_iommu.c
drivers/iommu/mtk_iommu.c
drivers/iommu/mtk_iommu.h
drivers/iommu/mtk_iommu_v1.c
drivers/iommu/omap-iommu.c
drivers/iommu/omap-iommu.h
drivers/iommu/qcom_iommu.c
drivers/iommu/rockchip-iommu.c
drivers/iommu/s390-iommu.c
drivers/iommu/tegra-gart.c
drivers/iommu/tegra-smmu.c
drivers/iommu/virtio-iommu.c
drivers/irqchip/irq-sifive-plic.c
drivers/isdn/capi/capi.c
drivers/md/dm-bufio.c
drivers/md/dm-dust.c
drivers/md/dm-integrity.c
drivers/md/dm-kcopyd.c
drivers/md/dm-raid.c
drivers/md/dm-table.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned-reclaim.c
drivers/md/dm-zoned-target.c
drivers/md/dm-zoned.h
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/media/platform/omap/omap_vout_vrfb.c
drivers/memory/mtk-smi.c
drivers/mfd/rk808.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/habanalabs/device.c
drivers/misc/habanalabs/goya/goya.c
drivers/misc/habanalabs/goya/goyaP.h
drivers/misc/habanalabs/habanalabs.h
drivers/misc/habanalabs/hw_queue.c
drivers/misc/habanalabs/include/goya/goya_packets.h
drivers/misc/habanalabs/irq.c
drivers/misc/habanalabs/memory.c
drivers/misc/ioc4.c [deleted file]
drivers/misc/lkdtm/bugs.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/pci-me.c
drivers/misc/sgi-xp/Makefile
drivers/misc/sgi-xp/xp.h
drivers/misc/sgi-xp/xp_main.c
drivers/misc/sgi-xp/xp_nofault.S [deleted file]
drivers/misc/sgi-xp/xp_sn2.c [deleted file]
drivers/misc/sgi-xp/xp_uv.c
drivers/misc/sgi-xp/xpc.h
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/sgi-xp/xpc_partition.c
drivers/misc/sgi-xp/xpc_sn2.c [deleted file]
drivers/misc/sgi-xp/xpc_uv.c
drivers/misc/sgi-xp/xpnet.c
drivers/misc/vmw_balloon.c
drivers/misc/vmw_vmci/vmci_doorbell.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sd.c
drivers/mmc/host/bcm2835.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-pci-o2micro.c
drivers/mmc/host/sdhci-sprd.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/uniphier-sd.c
drivers/mtd/hyperbus/Kconfig
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/spi-nor/spi-nor.c
drivers/net/bonding/bond_main.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/microchip/ksz9477_spi.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/aquantia/atlantic/aq_filters.c
drivers/net/ethernet/aquantia/atlantic/aq_main.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_vec.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/cavium/common/cavium_ptp.c
drivers/net/ethernet/cavium/liquidio/request_manager.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/ezchip/nps_enet.h
drivers/net/ethernet/freescale/enetc/enetc_ptp.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mscc/ocelot_ace.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/natsemi/sonic.c
drivers/net/ethernet/netronome/nfp/bpf/jit.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/seeq/sgiseeq.c
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/hamradio/6pack.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/ieee802154/mac802154_hwsim.c
drivers/net/netdevsim/dev.c
drivers/net/netdevsim/fib.c
drivers/net/netdevsim/netdev.c
drivers/net/netdevsim/netdevsim.h
drivers/net/phy/at803x.c
drivers/net/phy/phy-c45.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/phylink.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cx82310_eth.c
drivers/net/usb/kalmia.c
drivers/net/usb/lan78xx.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wimax/i2400m/fw.c
drivers/net/wimax/i2400m/op-rfkill.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
drivers/net/wireless/marvell/mwifiex/ie.c
drivers/net/wireless/marvell/mwifiex/uap_cmd.c
drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/ralink/rt2x00/rt2x00.h
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
drivers/net/wireless/rsi/rsi_91x_usb.c
drivers/net/xen-netback/netback.c
drivers/nfc/st95hf/core.c
drivers/nvdimm/pfn_devs.c
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/loop.c
drivers/nvme/target/nvmet.h
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/resolver.c
drivers/parisc/dino.c
drivers/parisc/eisa_enumerator.c
drivers/parisc/hppb.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/sgi_hotplug.c [deleted file]
drivers/pci/pcie/aspm.c
drivers/pci/quirks.c
drivers/perf/arm_smmuv3_pmu.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
drivers/perf/qcom_l2_pmu.c
drivers/perf/xgene_pmu.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
drivers/pinctrl/aspeed/pinmux-aspeed.c
drivers/pinctrl/aspeed/pinmux-aspeed.h
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/pinctrl-stmfx.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
drivers/platform/chrome/cros_ec_ishtp.c
drivers/platform/chrome/cros_ec_spi.c
drivers/platform/x86/intel_int0002_vgpio.c
drivers/power/supply/ab8500_charger.c
drivers/ras/Makefile
drivers/ras/cec.c
drivers/ras/debugfs.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/act8865-regulator.c
drivers/regulator/act8945a-regulator.c
drivers/regulator/core.c
drivers/regulator/da9062-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/da9211-regulator.c
drivers/regulator/fixed.c
drivers/regulator/helpers.c
drivers/regulator/lm363x-regulator.c
drivers/regulator/lp87565-regulator.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686-regulator.c
drivers/regulator/max8660.c
drivers/regulator/mt6358-regulator.c [new file with mode: 0644]
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/slg51000-regulator.c
drivers/regulator/stm32-booster.c
drivers/regulator/sy8824x.c [new file with mode: 0644]
drivers/regulator/tps65132-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/twl6030-regulator.c
drivers/regulator/uniphier-regulator.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/qla1280.c
drivers/scsi/qla1280.h
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/ufs/ufshcd.c
drivers/sn/Kconfig [deleted file]
drivers/sn/Makefile [deleted file]
drivers/sn/ioc3.c [deleted file]
drivers/soc/ixp4xx/Kconfig
drivers/soc/qcom/qcom-geni-se.c
drivers/soc/ti/pm33xx.c
drivers/soundwire/Kconfig
drivers/soundwire/Makefile
drivers/soundwire/cadence_master.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel-quadspi.c
drivers/spi/spi-altera.c
drivers/spi/spi-armada-3700.c
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-axi-spi-engine.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-cadence.c
drivers/spi/spi-cavium-octeon.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw-pci.c
drivers/spi/spi-efm32.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-fsl-cpm.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-lib.h
drivers/spi/spi-fsl-qspi.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-geni-qcom.c
drivers/spi/spi-gpio.c
drivers/spi/spi-lantiq-ssc.c
drivers/spi/spi-lp8841-rtc.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-meson-spifc.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-mt7621.c
drivers/spi/spi-mxs.c
drivers/spi/spi-npcm-fiu.c [new file with mode: 0644]
drivers/spi/spi-npcm-pspi.c
drivers/spi/spi-nuc900.c
drivers/spi/spi-nxp-fspi.c
drivers/spi/spi-oc-tiny.c
drivers/spi/spi-pic32-sqi.c
drivers/spi/spi-pic32.c
drivers/spi/spi-qcom-qspi.c
drivers/spi/spi-rb4xx.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sh.c
drivers/spi/spi-sifive.c
drivers/spi/spi-sirf.c
drivers/spi/spi-slave-mt27xx.c
drivers/spi/spi-sprd-adi.c
drivers/spi/spi-sprd.c
drivers/spi/spi-st-ssc4.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-sun4i.c
drivers/spi/spi-sun6i.c
drivers/spi/spi-synquacer.c
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-uniphier.c
drivers/spi/spi-xlp.c
drivers/spi/spi-zynq-qspi.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/staging/comedi/drivers/dt3000.c
drivers/target/target_core_user.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/ioc3_serial.c [deleted file]
drivers/tty/serial/ioc4_serial.c [deleted file]
drivers/tty/serial/sn_console.c [deleted file]
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/udc.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usbtmc.c
drivers/usb/core/buffer.c
drivers/usb/core/file.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/message.c
drivers/usb/dwc2/hcd.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/lpc32xx_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/host/fotg210-hcd.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/xhci-rcar.c
drivers/usb/host/xhci-tegra.c
drivers/usb/serial/option.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/tcpm/tcpm.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/test.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/fbdev/acornfb.c
drivers/video/fbdev/atafb.c
drivers/virtio/virtio_ring.c
drivers/watchdog/wdt285.c
drivers/xen/swiotlb-xen.c
fs/afs/cell.c
fs/afs/cmservice.c
fs/afs/dir.c
fs/afs/file.c
fs/afs/vlclient.c
fs/afs/yfsclient.c
fs/block_dev.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/inode.c
fs/ceph/locks.c
fs/ceph/snap.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/cifsfs.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/misc.c
fs/cifs/sess.c
fs/configfs/configfs_internal.h
fs/configfs/dir.c
fs/configfs/file.c
fs/ext4/inode.c
fs/io_uring.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4file.c
fs/nfs/pagelist.c
fs/nfs/pnfs_nfs.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/nfscache.c
fs/nfsd/nfsctl.c
fs/read_write.c
fs/seq_file.c
fs/ubifs/budget.c
fs/ubifs/orphan.c
fs/ubifs/super.c
fs/userfaultfd.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_dir2_node.c
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_log.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_reflink.c
include/asm-generic/5level-fixup.h
include/asm-generic/error-injection.h
include/dt-bindings/memory/mt8183-larb-port.h [new file with mode: 0644]
include/dt-bindings/regulator/active-semi,8865-regulator.h [new file with mode: 0644]
include/linux/acpi.h
include/linux/amd-iommu.h
include/linux/arch_topology.h
include/linux/ceph/buffer.h
include/linux/compiler.h
include/linux/cpuidle.h
include/linux/dma-contiguous.h
include/linux/dma-noncoherent.h
include/linux/edac.h
include/linux/error-injection.h
include/linux/gfp.h
include/linux/gpio.h
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
include/linux/i3c/device.h
include/linux/i3c/master.h
include/linux/input/elan-i2c-ids.h
include/linux/intel-iommu.h
include/linux/io-pgtable.h
include/linux/ioc4.h [deleted file]
include/linux/iommu.h
include/linux/kexec.h
include/linux/key.h
include/linux/logic_pio.h
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mlx5/device.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/netfilter/nf_conntrack_h323_types.h
include/linux/of_gpio.h
include/linux/omap-iommu.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/phy_fixed.h
include/linux/pid.h
include/linux/platform_data/gpio-htc-egpio.h
include/linux/platform_data/iommu-omap.h
include/linux/psci.h
include/linux/random.h
include/linux/regulator/consumer.h
include/linux/regulator/mt6358-regulator.h [new file with mode: 0644]
include/linux/signal.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/sunrpc/sched.h
include/linux/swiotlb.h
include/linux/syscalls.h
include/linux/timekeeper_internal.h
include/linux/topology.h
include/linux/trace_events.h
include/linux/usb.h
include/linux/usb/hcd.h
include/math-emu/op-common.h
include/misc/charlcd.h [deleted file]
include/net/act_api.h
include/net/addrconf.h
include/net/bluetooth/hci_core.h
include/net/inet_frag.h
include/net/ip_fib.h
include/net/net_namespace.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nf_tables_offload.h
include/net/netlink.h
include/net/nexthop.h
include/net/pkt_cls.h
include/net/psample.h
include/net/route.h
include/net/sock.h
include/net/xfrm.h
include/rdma/restrack.h
include/soc/arc/mcip.h
include/soc/mediatek/smi.h
include/trace/events/intel_iommu.h [new file with mode: 0644]
include/trace/events/rxrpc.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/bpf.h
include/uapi/linux/isdn/capicmd.h
include/uapi/linux/jffs2.h
include/uapi/linux/kexec.h
include/uapi/linux/netfilter/xt_nfacct.h
include/uapi/linux/prctl.h
include/uapi/linux/rds.h
include/uapi/linux/wait.h
include/uapi/rdma/siw-abi.h
init/Kconfig
ipc/util.h
kernel/Makefile
kernel/bpf/core.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/configs.c
kernel/dma/contiguous.c
kernel/dma/direct.c
kernel/dma/mapping.c
kernel/dma/remap.c
kernel/dma/swiotlb.c
kernel/events/hw_breakpoint.c
kernel/exit.c
kernel/fork.c
kernel/irq/irqdesc.c
kernel/irq/proc.c
kernel/irq/resend.c
kernel/jump_label.c
kernel/kallsyms.c
kernel/kexec_elf.c [new file with mode: 0644]
kernel/kprobes.c
kernel/module.c
kernel/sched/core.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/fair.c
kernel/sched/psi.c
kernel/signal.c
kernel/sys.c
kernel/time/timekeeping.c
kernel/time/vsyscall.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_probe.c
lib/Kconfig
lib/kfifo.c
lib/logic_pio.c
mm/balloon_compaction.c
mm/huge_memory.c
mm/hugetlb.c
mm/kasan/common.c
mm/kmemleak.c
mm/memcontrol.c
mm/mempolicy.c
mm/memremap.c
mm/page_alloc.c
mm/rmap.c
mm/shmem.c
mm/usercopy.c
mm/vmalloc.c
mm/vmscan.c
mm/workingset.c
mm/z3fold.c
mm/zsmalloc.c
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_v_ogm.c
net/batman-adv/multicast.c
net/batman-adv/netlink.c
net/bluetooth/hci_core.c
net/bluetooth/hci_debugfs.c
net/bluetooth/hci_event.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bridge/br_mdb.c
net/bridge/br_netfilter_hooks.c
net/bridge/netfilter/ebtables.c
net/bridge/netfilter/nft_meta_bridge.c
net/ceph/crypto.c
net/ceph/osd_client.c
net/core/dev.c
net/core/filter.c
net/core/flow_dissector.c
net/core/netpoll.c
net/core/skbuff.c
net/core/sock.c
net/core/sock_diag.c
net/core/sock_map.c
net/core/stream.c
net/dsa/switch.c
net/dsa/tag_8021q.c
net/ieee802154/6lowpan/reassembly.c
net/ieee802154/socket.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_fragment.c
net/ipv4/ip_fragment.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/ipv6/mcast.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/ping.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/mac80211/cfg.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mpls/mpls_iptunnel.c
net/ncsi/ncsi-cmd.c
net/ncsi/ncsi-rsp.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_offload.c
net/netfilter/nft_fib_netdev.c
net/netfilter/nft_flow_offload.c
net/netfilter/nft_socket.c
net/netfilter/xt_nfacct.c
net/netfilter/xt_physdev.c
net/openvswitch/conntrack.c
net/openvswitch/flow.c
net/openvswitch/flow.h
net/packet/af_packet.c
net/psample/psample.c
net/qrtr/tun.c
net/rds/bind.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/rdma_transport.c
net/rds/recv.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_event.c
net/rxrpc/call_object.c
net/rxrpc/conn_client.c
net/rxrpc/conn_event.c
net/rxrpc/conn_object.c
net/rxrpc/input.c
net/rxrpc/local_event.c
net/rxrpc/local_object.c
net/rxrpc/output.c
net/rxrpc/peer_event.c
net/rxrpc/protocol.h
net/rxrpc/recvmsg.c
net/rxrpc/rxkad.c
net/rxrpc/sendmsg.c
net/rxrpc/skbuff.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_ct.c
net/sched/act_ctinfo.c
net/sched/act_gact.c
net/sched/act_ife.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_mpls.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/sch_api.c
net/sched/sch_cbs.c
net/sched/sch_generic.c
net/sched/sch_hhf.c
net/sched/sch_taprio.c
net/sctp/protocol.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/stream.c
net/smc/smc_tx.c
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/tipc/addr.c
net/tipc/link.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tls/tls_device.c
net/tls/tls_main.c
net/wireless/reg.c
net/wireless/util.c
net/xdp/xdp_umem.c
net/xfrm/xfrm_interface.c
net/xfrm/xfrm_policy.c
samples/auxdisplay/cfag12864b-example.c
scripts/Makefile.kasan
scripts/coccinelle/api/atomic_as_refcounter.cocci
scripts/tools-support-relr.sh [new file with mode: 0755]
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_fifo.h
sound/firewire/oxfw/oxfw-pcm.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/usb/line6/pcm.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
tools/arch/riscv/include/uapi/asm/perf_regs.h [new file with mode: 0644]
tools/bpf/bpftool/common.c
tools/bpf/bpftool/prog.c
tools/hv/hv_get_dhcp_info.sh
tools/hv/hv_kvp_daemon.c
tools/hv/hv_set_ifconfig.sh
tools/hv/hv_vss_daemon.c
tools/hv/lsvmbus
tools/include/uapi/linux/bpf.h
tools/lib/bpf/libbpf.c
tools/perf/Makefile.config
tools/perf/arch/riscv/Build [new file with mode: 0644]
tools/perf/arch/riscv/Makefile [new file with mode: 0644]
tools/perf/arch/riscv/include/perf_regs.h [new file with mode: 0644]
tools/perf/arch/riscv/util/Build [new file with mode: 0644]
tools/perf/arch/riscv/util/dwarf-regs.c [new file with mode: 0644]
tools/perf/arch/riscv/util/unwind-libdw.c [new file with mode: 0644]
tools/power/x86/turbostat/Makefile
tools/power/x86/turbostat/turbostat.c
tools/power/x86/x86_energy_perf_policy/Makefile
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
tools/testing/selftests/arm64/.gitignore [new file with mode: 0644]
tools/testing/selftests/arm64/Makefile [new file with mode: 0644]
tools/testing/selftests/arm64/run_tags_test.sh [new file with mode: 0755]
tools/testing/selftests/arm64/tags_test.c [new file with mode: 0644]
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/config
tools/testing/selftests/bpf/test_btf_dump.c
tools/testing/selftests/bpf/test_cgroup_storage.c
tools/testing/selftests/bpf/test_sock.c
tools/testing/selftests/bpf/verifier/loops1.c
tools/testing/selftests/cgroup/test_freezer.c
tools/testing/selftests/kvm/include/evmcs.h
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/vmx.c
tools/testing/selftests/kvm/x86_64/evmcs_test.c
tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c
tools/testing/selftests/kvm/x86_64/platform_info_test.c
tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
tools/testing/selftests/net/fib_nexthops.sh
tools/testing/selftests/net/tcp_fastopen_backup_key.sh
tools/testing/selftests/net/xfrm_policy.sh
tools/testing/selftests/netfilter/nft_flowtable.sh
tools/testing/selftests/pidfd/.gitignore
tools/testing/selftests/pidfd/Makefile
tools/testing/selftests/pidfd/pidfd.h
tools/testing/selftests/pidfd/pidfd_open_test.c
tools/testing/selftests/pidfd/pidfd_poll_test.c [new file with mode: 0644]
tools/testing/selftests/pidfd/pidfd_test.c
tools/testing/selftests/pidfd/pidfd_wait.c [new file with mode: 0644]
tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py
tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json
virt/kvm/arm/mmio.c
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-mmio.c
virt/kvm/arm/vgic/vgic-v2.c
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.c

index 2ffd69a..196ca31 100644 (file)
@@ -107,10 +107,13 @@ ForEachMacros:
   - 'css_for_each_descendant_post'
   - 'css_for_each_descendant_pre'
   - 'device_for_each_child_node'
+  - 'dma_fence_chain_for_each'
   - 'drm_atomic_crtc_for_each_plane'
   - 'drm_atomic_crtc_state_for_each_plane'
   - 'drm_atomic_crtc_state_for_each_plane_state'
   - 'drm_atomic_for_each_plane_damage'
+  - 'drm_client_for_each_connector_iter'
+  - 'drm_client_for_each_modeset'
   - 'drm_connector_for_each_possible_encoder'
   - 'drm_for_each_connector_iter'
   - 'drm_for_each_crtc'
@@ -126,6 +129,7 @@ ForEachMacros:
   - 'drm_mm_for_each_node_in_range'
   - 'drm_mm_for_each_node_safe'
   - 'flow_action_for_each'
+  - 'for_each_active_dev_scope'
   - 'for_each_active_drhd_unit'
   - 'for_each_active_iommu'
   - 'for_each_available_child_of_node'
@@ -153,6 +157,8 @@ ForEachMacros:
   - 'for_each_cpu_not'
   - 'for_each_cpu_wrap'
   - 'for_each_dev_addr'
+  - 'for_each_dev_scope'
+  - 'for_each_displayid_db'
   - 'for_each_dma_cap_mask'
   - 'for_each_dpcm_be'
   - 'for_each_dpcm_be_rollback'
@@ -169,6 +175,8 @@ ForEachMacros:
   - 'for_each_evictable_lru'
   - 'for_each_fib6_node_rt_rcu'
   - 'for_each_fib6_walker_rt'
+  - 'for_each_free_mem_pfn_range_in_zone'
+  - 'for_each_free_mem_pfn_range_in_zone_from'
   - 'for_each_free_mem_range'
   - 'for_each_free_mem_range_reverse'
   - 'for_each_func_rsrc'
@@ -178,6 +186,7 @@ ForEachMacros:
   - 'for_each_ip_tunnel_rcu'
   - 'for_each_irq_nr'
   - 'for_each_link_codecs'
+  - 'for_each_link_platforms'
   - 'for_each_lru'
   - 'for_each_matching_node'
   - 'for_each_matching_node_and_match'
@@ -302,7 +311,10 @@ ForEachMacros:
   - 'ide_port_for_each_present_dev'
   - 'idr_for_each_entry'
   - 'idr_for_each_entry_continue'
+  - 'idr_for_each_entry_continue_ul'
   - 'idr_for_each_entry_ul'
+  - 'in_dev_for_each_ifa_rcu'
+  - 'in_dev_for_each_ifa_rtnl'
   - 'inet_bind_bucket_for_each'
   - 'inet_lhash2_for_each_icsk_rcu'
   - 'key_for_each'
@@ -343,8 +355,6 @@ ForEachMacros:
   - 'media_device_for_each_intf'
   - 'media_device_for_each_link'
   - 'media_device_for_each_pad'
-  - 'mp_bvec_for_each_page'
-  - 'mp_bvec_for_each_segment'
   - 'nanddev_io_for_each_page'
   - 'netdev_for_each_lower_dev'
   - 'netdev_for_each_lower_private'
@@ -381,18 +391,19 @@ ForEachMacros:
   - 'radix_tree_for_each_slot'
   - 'radix_tree_for_each_tagged'
   - 'rbtree_postorder_for_each_entry_safe'
+  - 'rdma_for_each_block'
   - 'rdma_for_each_port'
   - 'resource_list_for_each_entry'
   - 'resource_list_for_each_entry_safe'
   - 'rhl_for_each_entry_rcu'
   - 'rhl_for_each_rcu'
   - 'rht_for_each'
-  - 'rht_for_each_from'
   - 'rht_for_each_entry'
   - 'rht_for_each_entry_from'
   - 'rht_for_each_entry_rcu'
   - 'rht_for_each_entry_rcu_from'
   - 'rht_for_each_entry_safe'
+  - 'rht_for_each_from'
   - 'rht_for_each_rcu'
   - 'rht_for_each_rcu_from'
   - '__rq_for_each_bio'
index 255a149..1ad4fd6 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -64,6 +64,9 @@ Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@imgtec.com>
 Dengcheng Zhu <dzhu@wavecomp.com> <dczhu@mips.com>
 Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@gmail.com>
 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+Dmitry Safonov <0x7f454c46@gmail.com> <dsafonov@virtuozzo.com>
+Dmitry Safonov <0x7f454c46@gmail.com> <d.safonov@partner.samsung.com>
+Dmitry Safonov <0x7f454c46@gmail.com> <dima@arista.com>
 Domen Puncer <domen@coderock.org>
 Douglas Gilbert <dougg@torque.net>
 Ed L. Cashin <ecashin@coraid.com>
@@ -160,6 +163,8 @@ Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.co
 Matt Ranostay <mranostay@gmail.com> <matt.ranostay@intel.com>
 Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting>
 Matt Redfearn <matt.redfearn@mips.com> <matt.redfearn@imgtec.com>
+Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com>
+Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com>
 Mayuresh Janorkar <mayur@ti.com>
 Michael Buesch <m@bues.ch>
 Michel Dänzer <michel@tungstengraphics.com>
index f4c6121..6768305 100644 (file)
@@ -9,7 +9,7 @@ Linux PCI Bus Subsystem
    :numbered:
 
    pci
-   picebus-howto
+   pciebus-howto
    pci-iov-howto
    msi-howto
    acpi-info
diff --git a/Documentation/PCI/pciebus-howto.rst b/Documentation/PCI/pciebus-howto.rst
new file mode 100644 (file)
index 0000000..f882ff6
--- /dev/null
@@ -0,0 +1,220 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+===========================================
+The PCI Express Port Bus Driver Guide HOWTO
+===========================================
+
+:Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
+:Copyright: |copy| 2004 Intel Corporation
+
+About this guide
+================
+
+This guide describes the basics of the PCI Express Port Bus driver
+and provides information on how to enable the service drivers to
+register/unregister with the PCI Express Port Bus Driver.
+
+
+What is the PCI Express Port Bus Driver
+=======================================
+
+A PCI Express Port is a logical PCI-PCI Bridge structure. There
+are two types of PCI Express Port: the Root Port and the Switch
+Port. The Root Port originates a PCI Express link from a PCI Express
+Root Complex and the Switch Port connects PCI Express links to
+internal logical PCI buses. The Switch Port, which has its secondary
+bus representing the switch's internal routing logic, is called the
+switch's Upstream Port. The switch's Downstream Port is bridging from
+switch's internal routing bus to a bus representing the downstream
+PCI Express link from the PCI Express Switch.
+
+A PCI Express Port can provide up to four distinct functions,
+referred to in this document as services, depending on its port type.
+PCI Express Port's services include native hotplug support (HP),
+power management event support (PME), advanced error reporting
+support (AER), and virtual channel support (VC). These services may
+be handled by a single complex driver or be individually distributed
+and handled by corresponding service drivers.
+
+Why use the PCI Express Port Bus Driver?
+========================================
+
+In existing Linux kernels, the Linux Device Driver Model allows a
+physical device to be handled by only a single driver. The PCI
+Express Port is a PCI-PCI Bridge device with multiple distinct
+services. To maintain a clean and simple solution each service
+may have its own software service driver. In this case several
+service drivers will compete for a single PCI-PCI Bridge device.
+For example, if the PCI Express Root Port native hotplug service
+driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
+kernel therefore does not load other service drivers for that Root
+Port. In other words, it is impossible to have multiple service
+drivers load and run on a PCI-PCI Bridge device simultaneously
+using the current driver model.
+
+To enable multiple service drivers running simultaneously requires
+having a PCI Express Port Bus driver, which manages all populated
+PCI Express Ports and distributes all provided service requests
+to the corresponding service drivers as required. Some key
+advantages of using the PCI Express Port Bus driver are listed below:
+
+  - Allow multiple service drivers to run simultaneously on
+    a PCI-PCI Bridge Port device.
+
+  - Allow service drivers implemented in an independent
+    staged approach.
+
+  - Allow one service driver to run on multiple PCI-PCI Bridge
+    Port devices.
+
+  - Manage and distribute resources of a PCI-PCI Bridge Port
+    device to requested service drivers.
+
+Configuring the PCI Express Port Bus Driver vs. Service Drivers
+===============================================================
+
+Including the PCI Express Port Bus Driver Support into the Kernel
+-----------------------------------------------------------------
+
+Including the PCI Express Port Bus driver depends on whether the PCI
+Express support is included in the kernel config. The kernel will
+automatically include the PCI Express Port Bus driver as a kernel
+driver when the PCI Express support is enabled in the kernel.
+
+Enabling Service Driver Support
+-------------------------------
+
+PCI device drivers are implemented based on Linux Device Driver Model.
+All service drivers are PCI device drivers. As discussed above, it is
+impossible to load any service driver once the kernel has loaded the
+PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
+Model requires some minimal changes on existing service drivers that
+imposes no impact on the functionality of existing service drivers.
+
+A service driver is required to use the two APIs shown below to
+register its service with the PCI Express Port Bus driver (see
+section 5.2.1 & 5.2.2). It is important that a service driver
+initializes the pcie_port_service_driver data structure, included in
+header file /include/linux/pcieport_if.h, before calling these APIs.
+Failure to do so will result an identity mismatch, which prevents
+the PCI Express Port Bus driver from loading a service driver.
+
+pcie_port_service_register
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+  int pcie_port_service_register(struct pcie_port_service_driver *new)
+
+This API replaces the Linux Driver Model's pci_register_driver API. A
+service driver should always calls pcie_port_service_register at
+module init. Note that after service driver being loaded, calls
+such as pci_enable_device(dev) and pci_set_master(dev) are no longer
+necessary since these calls are executed by the PCI Port Bus driver.
+
+pcie_port_service_unregister
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+  void pcie_port_service_unregister(struct pcie_port_service_driver *new)
+
+pcie_port_service_unregister replaces the Linux Driver Model's
+pci_unregister_driver. It's always called by service driver when a
+module exits.
+
+Sample Code
+~~~~~~~~~~~
+
+Below is sample service driver code to initialize the port service
+driver data structure.
+::
+
+  static struct pcie_port_service_id service_id[] = { {
+    .vendor = PCI_ANY_ID,
+    .device = PCI_ANY_ID,
+    .port_type = PCIE_RC_PORT,
+    .service_type = PCIE_PORT_SERVICE_AER,
+    }, { /* end: all zeroes */ }
+  };
+
+  static struct pcie_port_service_driver root_aerdrv = {
+    .name              = (char *)device_name,
+    .id_table  = &service_id[0],
+
+    .probe             = aerdrv_load,
+    .remove            = aerdrv_unload,
+
+    .suspend   = aerdrv_suspend,
+    .resume            = aerdrv_resume,
+  };
+
+Below is a sample code for registering/unregistering a service
+driver.
+::
+
+  static int __init aerdrv_service_init(void)
+  {
+    int retval = 0;
+
+    retval = pcie_port_service_register(&root_aerdrv);
+    if (!retval) {
+      /*
+      * FIX ME
+      */
+    }
+    return retval;
+  }
+
+  static void __exit aerdrv_service_exit(void)
+  {
+    pcie_port_service_unregister(&root_aerdrv);
+  }
+
+  module_init(aerdrv_service_init);
+  module_exit(aerdrv_service_exit);
+
+Possible Resource Conflicts
+===========================
+
+Since all service drivers of a PCI-PCI Bridge Port device are
+allowed to run simultaneously, below lists a few of possible resource
+conflicts with proposed solutions.
+
+MSI and MSI-X Vector Resource
+-----------------------------
+
+Once MSI or MSI-X interrupts are enabled on a device, it stays in this
+mode until they are disabled again.  Since service drivers of the same
+PCI-PCI Bridge port share the same physical device, if an individual
+service driver enables or disables MSI/MSI-X mode it may result
+unpredictable behavior.
+
+To avoid this situation all service drivers are not permitted to
+switch interrupt mode on its device. The PCI Express Port Bus driver
+is responsible for determining the interrupt mode and this should be
+transparent to service drivers. Service drivers need to know only
+the vector IRQ assigned to the field irq of struct pcie_device, which
+is passed in when the PCI Express Port Bus driver probes each service
+driver. Service drivers should use (struct pcie_device*)dev->irq to
+call request_irq/free_irq. In addition, the interrupt mode is stored
+in the field interrupt_mode of struct pcie_device.
+
+PCI Memory/IO Mapped Regions
+----------------------------
+
+Service drivers for PCI Express Power Management (PME), Advanced
+Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
+PCI configuration space on the PCI Express port. In all cases the
+registers accessed are independent of each other. This patch assumes
+that all service drivers will be well behaved and not overwrite
+other service driver's configuration settings.
+
+PCI Config Registers
+--------------------
+
+Each service driver runs its PCI config operations on its own
+capability structure except the PCI Express capability structure, in
+which Root Control register and Device Control register are shared
+between PME and AER. This patch assumes that all service drivers
+will be well behaved and not overwrite other service driver's
+configuration settings.
diff --git a/Documentation/PCI/picebus-howto.rst b/Documentation/PCI/picebus-howto.rst
deleted file mode 100644 (file)
index f882ff6..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===========================================
-The PCI Express Port Bus Driver Guide HOWTO
-===========================================
-
-:Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
-:Copyright: |copy| 2004 Intel Corporation
-
-About this guide
-================
-
-This guide describes the basics of the PCI Express Port Bus driver
-and provides information on how to enable the service drivers to
-register/unregister with the PCI Express Port Bus Driver.
-
-
-What is the PCI Express Port Bus Driver
-=======================================
-
-A PCI Express Port is a logical PCI-PCI Bridge structure. There
-are two types of PCI Express Port: the Root Port and the Switch
-Port. The Root Port originates a PCI Express link from a PCI Express
-Root Complex and the Switch Port connects PCI Express links to
-internal logical PCI buses. The Switch Port, which has its secondary
-bus representing the switch's internal routing logic, is called the
-switch's Upstream Port. The switch's Downstream Port is bridging from
-switch's internal routing bus to a bus representing the downstream
-PCI Express link from the PCI Express Switch.
-
-A PCI Express Port can provide up to four distinct functions,
-referred to in this document as services, depending on its port type.
-PCI Express Port's services include native hotplug support (HP),
-power management event support (PME), advanced error reporting
-support (AER), and virtual channel support (VC). These services may
-be handled by a single complex driver or be individually distributed
-and handled by corresponding service drivers.
-
-Why use the PCI Express Port Bus Driver?
-========================================
-
-In existing Linux kernels, the Linux Device Driver Model allows a
-physical device to be handled by only a single driver. The PCI
-Express Port is a PCI-PCI Bridge device with multiple distinct
-services. To maintain a clean and simple solution each service
-may have its own software service driver. In this case several
-service drivers will compete for a single PCI-PCI Bridge device.
-For example, if the PCI Express Root Port native hotplug service
-driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
-kernel therefore does not load other service drivers for that Root
-Port. In other words, it is impossible to have multiple service
-drivers load and run on a PCI-PCI Bridge device simultaneously
-using the current driver model.
-
-To enable multiple service drivers running simultaneously requires
-having a PCI Express Port Bus driver, which manages all populated
-PCI Express Ports and distributes all provided service requests
-to the corresponding service drivers as required. Some key
-advantages of using the PCI Express Port Bus driver are listed below:
-
-  - Allow multiple service drivers to run simultaneously on
-    a PCI-PCI Bridge Port device.
-
-  - Allow service drivers implemented in an independent
-    staged approach.
-
-  - Allow one service driver to run on multiple PCI-PCI Bridge
-    Port devices.
-
-  - Manage and distribute resources of a PCI-PCI Bridge Port
-    device to requested service drivers.
-
-Configuring the PCI Express Port Bus Driver vs. Service Drivers
-===============================================================
-
-Including the PCI Express Port Bus Driver Support into the Kernel
------------------------------------------------------------------
-
-Including the PCI Express Port Bus driver depends on whether the PCI
-Express support is included in the kernel config. The kernel will
-automatically include the PCI Express Port Bus driver as a kernel
-driver when the PCI Express support is enabled in the kernel.
-
-Enabling Service Driver Support
--------------------------------
-
-PCI device drivers are implemented based on Linux Device Driver Model.
-All service drivers are PCI device drivers. As discussed above, it is
-impossible to load any service driver once the kernel has loaded the
-PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
-Model requires some minimal changes on existing service drivers that
-imposes no impact on the functionality of existing service drivers.
-
-A service driver is required to use the two APIs shown below to
-register its service with the PCI Express Port Bus driver (see
-section 5.2.1 & 5.2.2). It is important that a service driver
-initializes the pcie_port_service_driver data structure, included in
-header file /include/linux/pcieport_if.h, before calling these APIs.
-Failure to do so will result an identity mismatch, which prevents
-the PCI Express Port Bus driver from loading a service driver.
-
-pcie_port_service_register
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-::
-
-  int pcie_port_service_register(struct pcie_port_service_driver *new)
-
-This API replaces the Linux Driver Model's pci_register_driver API. A
-service driver should always calls pcie_port_service_register at
-module init. Note that after service driver being loaded, calls
-such as pci_enable_device(dev) and pci_set_master(dev) are no longer
-necessary since these calls are executed by the PCI Port Bus driver.
-
-pcie_port_service_unregister
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-::
-
-  void pcie_port_service_unregister(struct pcie_port_service_driver *new)
-
-pcie_port_service_unregister replaces the Linux Driver Model's
-pci_unregister_driver. It's always called by service driver when a
-module exits.
-
-Sample Code
-~~~~~~~~~~~
-
-Below is sample service driver code to initialize the port service
-driver data structure.
-::
-
-  static struct pcie_port_service_id service_id[] = { {
-    .vendor = PCI_ANY_ID,
-    .device = PCI_ANY_ID,
-    .port_type = PCIE_RC_PORT,
-    .service_type = PCIE_PORT_SERVICE_AER,
-    }, { /* end: all zeroes */ }
-  };
-
-  static struct pcie_port_service_driver root_aerdrv = {
-    .name              = (char *)device_name,
-    .id_table  = &service_id[0],
-
-    .probe             = aerdrv_load,
-    .remove            = aerdrv_unload,
-
-    .suspend   = aerdrv_suspend,
-    .resume            = aerdrv_resume,
-  };
-
-Below is a sample code for registering/unregistering a service
-driver.
-::
-
-  static int __init aerdrv_service_init(void)
-  {
-    int retval = 0;
-
-    retval = pcie_port_service_register(&root_aerdrv);
-    if (!retval) {
-      /*
-      * FIX ME
-      */
-    }
-    return retval;
-  }
-
-  static void __exit aerdrv_service_exit(void)
-  {
-    pcie_port_service_unregister(&root_aerdrv);
-  }
-
-  module_init(aerdrv_service_init);
-  module_exit(aerdrv_service_exit);
-
-Possible Resource Conflicts
-===========================
-
-Since all service drivers of a PCI-PCI Bridge Port device are
-allowed to run simultaneously, below lists a few of possible resource
-conflicts with proposed solutions.
-
-MSI and MSI-X Vector Resource
------------------------------
-
-Once MSI or MSI-X interrupts are enabled on a device, it stays in this
-mode until they are disabled again.  Since service drivers of the same
-PCI-PCI Bridge port share the same physical device, if an individual
-service driver enables or disables MSI/MSI-X mode it may result
-unpredictable behavior.
-
-To avoid this situation all service drivers are not permitted to
-switch interrupt mode on its device. The PCI Express Port Bus driver
-is responsible for determining the interrupt mode and this should be
-transparent to service drivers. Service drivers need to know only
-the vector IRQ assigned to the field irq of struct pcie_device, which
-is passed in when the PCI Express Port Bus driver probes each service
-driver. Service drivers should use (struct pcie_device*)dev->irq to
-call request_irq/free_irq. In addition, the interrupt mode is stored
-in the field interrupt_mode of struct pcie_device.
-
-PCI Memory/IO Mapped Regions
-----------------------------
-
-Service drivers for PCI Express Power Management (PME), Advanced
-Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
-PCI configuration space on the PCI Express port. In all cases the
-registers accessed are independent of each other. This patch assumes
-that all service drivers will be well behaved and not overwrite
-other service driver's configuration settings.
-
-PCI Config Registers
---------------------
-
-Each service driver runs its PCI config operations on its own
-capability structure except the PCI Express capability structure, in
-which Root Control register and Device Control register are shared
-between PME and AER. This patch assumes that all service drivers
-will be well behaved and not overwrite other service driver's
-configuration settings.
index 47d981a..0d2a67e 100644 (file)
                        Note that using this option lowers the security
                        provided by tboot because it makes the system
                        vulnerable to DMA attacks.
+               nobounce [Default off]
+                       Disable bounce buffer for unstrusted devices such as
+                       the Thunderbolt devices. This will treat the untrusted
+                       devices as the trusted ones, hence might expose security
+                       risks of DMA attacks.
 
        intel_idle.max_cstate=  [KNL,HW,ACPI,X86]
                        0       disables intel_idle and fall back on acpi_idle.
                          synchronously.
 
        iommu.passthrough=
-                       [ARM64] Configure DMA to bypass the IOMMU by default.
+                       [ARM64, X86] Configure DMA to bypass the IOMMU by default.
                        Format: { "0" | "1" }
                        0 - Use IOMMU translation for DMA.
                        1 - Bypass the IOMMU for DMA.
 
        machvec=        [IA-64] Force the use of a particular machine-vector
                        (machvec) in a generic kernel.
-                       Example: machvec=hpzx1_swiotlb
+                       Example: machvec=hpzx1
 
        machtype=       [Loongson] Share the same kernel image file between different
                         yeeloong laptop.
                        Run specified binary instead of /init from the ramdisk,
                        used for early userspace startup. See initrd.
 
+       rdrand=         [X86]
+                       force - Override the decision by the kernel to hide the
+                               advertisement of RDRAND support (this affects
+                               certain AMD processors because of buggy BIOS
+                               support, specifically around the suspend/resume
+                               path).
+
        rdt=            [HW,X86,RDT]
                        Turn on/off individual RDT features. List is:
                        cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
diff --git a/Documentation/admin-guide/perf/imx-ddr.rst b/Documentation/admin-guide/perf/imx-ddr.rst
new file mode 100644 (file)
index 0000000..517a205
--- /dev/null
@@ -0,0 +1,52 @@
+=====================================================
+Freescale i.MX8 DDR Performance Monitoring Unit (PMU)
+=====================================================
+
+There are no performance counters inside the DRAM controller, so performance
+signals are brought out to the edge of the controller where a set of 4 x 32 bit
+counters is implemented. This is controlled by the CSV modes programed in counter
+control register which causes a large number of PERF signals to be generated.
+
+Selection of the value for each counter is done via the config registers. There
+is one register for each counter. Counter 0 is special in that it always counts
+“time” and when expired causes a lock on itself and the other counters and an
+interrupt is raised. If any other counter overflows, it continues counting, and
+no interrupt is raised.
+
+The "format" directory describes format of the config (event ID) and config1
+(AXI filtering) fields of the perf_event_attr structure, see /sys/bus/event_source/
+devices/imx8_ddr0/format/. The "events" directory describes the events types
+hardware supported that can be used with perf tool, see /sys/bus/event_source/
+devices/imx8_ddr0/events/.
+  e.g.::
+        perf stat -a -e imx8_ddr0/cycles/ cmd
+        perf stat -a -e imx8_ddr0/read/,imx8_ddr0/write/ cmd
+
+AXI filtering is only used by CSV modes 0x41 (axid-read) and 0x42 (axid-write)
+to count reading or writing matches filter setting. Filter setting is various
+from different DRAM controller implementations, which is distinguished by quirks
+in the driver.
+
+* With DDR_CAP_AXI_ID_FILTER quirk.
+  Filter is defined with two configuration parts:
+  --AXI_ID defines AxID matching value.
+  --AXI_MASKING defines which bits of AxID are meaningful for the matching.
+        0:corresponding bit is masked.
+        1: corresponding bit is not masked, i.e. used to do the matching.
+
+  AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter.
+  When non-masked bits are matching corresponding AXI_ID bits then counter is
+  incremented. Perf counter is incremented if
+          AxID && AXI_MASKING == AXI_ID && AXI_MASKING
+
+  This filter doesn't support filter different AXI ID for axid-read and axid-write
+  event at the same time as this filter is shared between counters.
+  e.g.::
+        perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
+        perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
+
+  NOTE: axi_mask is inverted in userspace(i.e. set bits are bits to mask), and
+  it will be reverted in driver automatically. so that the user can just specify
+  axi_id to monitor a specific id, rather than having to specify axi_mask.
+  e.g.::
+        perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12
index a7d44e7..287b987 100644 (file)
@@ -39,7 +39,6 @@ Table : Subdirectories in /proc/sys/net
  802       E802 protocol         ax25       AX25
  ethernet  Ethernet protocol     rose       X.25 PLP layer
  ipv4      IP version 4          x25        X.25 protocol
- ipx       IPX                   token-ring IBM token ring
  bridge    Bridging              decnet     DEC net
  ipv6      IP version 6          tipc       TIPC
  ========= =================== = ========== ==================
@@ -401,33 +400,7 @@ interface.
 (network) that the route leads to, the router (may be directly connected), the
 route flags, and the device the route is using.
 
-
-5. IPX
-------
-
-The IPX protocol has no tunable values in proc/sys/net.
-
-The IPX  protocol  does,  however,  provide  proc/net/ipx. This lists each IPX
-socket giving  the  local  and  remote  addresses  in  Novell  format (that is
-network:node:port). In  accordance  with  the  strange  Novell  tradition,
-everything but the port is in hex. Not_Connected is displayed for sockets that
-are not  tied to a specific remote address. The Tx and Rx queue sizes indicate
-the number  of  bytes  pending  for  transmission  and  reception.  The  state
-indicates the  state  the  socket  is  in and the uid is the owning uid of the
-socket.
-
-The /proc/net/ipx_interface  file lists all IPX interfaces. For each interface
-it gives  the network number, the node number, and indicates if the network is
-the primary  network.  It  also  indicates  which  device  it  is bound to (or
-Internal for  internal  networks)  and  the  Frame  Type if appropriate. Linux
-supports 802.3,  802.2,  802.2  SNAP  and DIX (Blue Book) ethernet framing for
-IPX.
-
-The /proc/net/ipx_route  table  holds  a list of IPX routes. For each route it
-gives the  destination  network, the router node (or Directly) and the network
-address of the router (or Connected) for internal networks.
-
-6. TIPC
+5. TIPC
 -------
 
 tipc_rmem
index 96b696b..5c0c69d 100644 (file)
@@ -16,6 +16,7 @@ ARM64 Architecture
     pointer-authentication
     silicon-errata
     sve
+    tagged-address-abi
     tagged-pointers
 
 .. only::  subproject and html
diff --git a/Documentation/arm64/kasan-offsets.sh b/Documentation/arm64/kasan-offsets.sh
new file mode 100644 (file)
index 0000000..2b7a021
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Print out the KASAN_SHADOW_OFFSETS required to place the KASAN SHADOW
+# start address at the mid-point of the kernel VA space
+
+print_kasan_offset () {
+       printf "%02d\t" $1
+       printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \
+                       + (1 << ($1 - 32 - $2)) \
+                       - (1 << (64 - 32 - $2)) ))
+}
+
+echo KASAN_SHADOW_SCALE_SHIFT = 3
+printf "VABITS\tKASAN_SHADOW_OFFSET\n"
+print_kasan_offset 48 3
+print_kasan_offset 47 3
+print_kasan_offset 42 3
+print_kasan_offset 39 3
+print_kasan_offset 36 3
+echo
+echo KASAN_SHADOW_SCALE_SHIFT = 4
+printf "VABITS\tKASAN_SHADOW_OFFSET\n"
+print_kasan_offset 48 4
+print_kasan_offset 47 4
+print_kasan_offset 42 4
+print_kasan_offset 39 4
+print_kasan_offset 36 4
index 464b880..b040909 100644 (file)
@@ -14,6 +14,10 @@ with the 4KB page configuration, allowing 39-bit (512GB) or 48-bit
 64KB pages, only 2 levels of translation tables, allowing 42-bit (4TB)
 virtual address, are used but the memory layout is the same.
 
+ARMv8.2 adds optional support for Large Virtual Address space. This is
+only available when running with a 64KB page size and expands the
+number of descriptors in the first level of translation.
+
 User addresses have bits 63:48 set to 0 while the kernel addresses have
 the same bits set to 1. TTBRx selection is given by bit 63 of the
 virtual address. The swapper_pg_dir contains only kernel (global)
@@ -22,40 +26,43 @@ The swapper_pg_dir address is written to TTBR1 and never written to
 TTBR0.
 
 
-AArch64 Linux memory layout with 4KB pages + 3 levels::
-
-  Start                        End                     Size            Use
-  -----------------------------------------------------------------------
-  0000000000000000     0000007fffffffff         512GB          user
-  ffffff8000000000     ffffffffffffffff         512GB          kernel
-
-
-AArch64 Linux memory layout with 4KB pages + 4 levels::
+AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
 
   Start                        End                     Size            Use
   -----------------------------------------------------------------------
   0000000000000000     0000ffffffffffff         256TB          user
-  ffff000000000000     ffffffffffffffff         256TB          kernel
-
-
-AArch64 Linux memory layout with 64KB pages + 2 levels::
+  ffff000000000000     ffff7fffffffffff         128TB          kernel logical memory map
+  ffff800000000000     ffff9fffffffffff          32TB          kasan shadow region
+  ffffa00000000000     ffffa00007ffffff         128MB          bpf jit region
+  ffffa00008000000     ffffa0000fffffff         128MB          modules
+  ffffa00010000000     fffffdffbffeffff         ~93TB          vmalloc
+  fffffdffbfff0000     fffffdfffe5f8fff        ~998MB          [guard region]
+  fffffdfffe5f9000     fffffdfffe9fffff        4124KB          fixed mappings
+  fffffdfffea00000     fffffdfffebfffff           2MB          [guard region]
+  fffffdfffec00000     fffffdffffbfffff          16MB          PCI I/O space
+  fffffdffffc00000     fffffdffffdfffff           2MB          [guard region]
+  fffffdffffe00000     ffffffffffdfffff           2TB          vmemmap
+  ffffffffffe00000     ffffffffffffffff           2MB          [guard region]
+
+
+AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support)::
 
   Start                        End                     Size            Use
   -----------------------------------------------------------------------
-  0000000000000000     000003ffffffffff           4TB          user
-  fffffc0000000000     ffffffffffffffff           4TB          kernel
-
-
-AArch64 Linux memory layout with 64KB pages + 3 levels::
-
-  Start                        End                     Size            Use
-  -----------------------------------------------------------------------
-  0000000000000000     0000ffffffffffff         256TB          user
-  ffff000000000000     ffffffffffffffff         256TB          kernel
-
-
-For details of the virtual kernel memory layout please see the kernel
-booting log.
+  0000000000000000     000fffffffffffff           4PB          user
+  fff0000000000000     fff7ffffffffffff           2PB          kernel logical memory map
+  fff8000000000000     fffd9fffffffffff        1440TB          [gap]
+  fffda00000000000     ffff9fffffffffff         512TB          kasan shadow region
+  ffffa00000000000     ffffa00007ffffff         128MB          bpf jit region
+  ffffa00008000000     ffffa0000fffffff         128MB          modules
+  ffffa00010000000     fffff81ffffeffff         ~88TB          vmalloc
+  fffff81fffff0000     fffffc1ffe58ffff          ~3TB          [guard region]
+  fffffc1ffe590000     fffffc1ffe9fffff        4544KB          fixed mappings
+  fffffc1ffea00000     fffffc1ffebfffff           2MB          [guard region]
+  fffffc1ffec00000     fffffc1fffbfffff          16MB          PCI I/O space
+  fffffc1fffc00000     fffffc1fffdfffff           2MB          [guard region]
+  fffffc1fffe00000     ffffffffffdfffff        3968GB          vmemmap
+  ffffffffffe00000     ffffffffffffffff           2MB          [guard region]
 
 
 Translation table lookup with 4KB pages::
@@ -83,7 +90,8 @@ Translation table lookup with 64KB pages::
    |                 |    |               |            [15:0]  in-page offset
    |                 |    |               +----------> [28:16] L3 index
    |                 |    +--------------------------> [41:29] L2 index
-   |                 +-------------------------------> [47:42] L1 index
+   |                 +-------------------------------> [47:42] L1 index (48-bit)
+   |                                                   [51:42] L1 index (52-bit)
    +-------------------------------------------------> [63] TTBR0/1
 
 
@@ -96,3 +104,62 @@ ARM64_HARDEN_EL2_VECTORS is selected for particular CPUs.
 
 When using KVM with the Virtualization Host Extensions, no additional
 mappings are created, since the host kernel runs directly in EL2.
+
+52-bit VA support in the kernel
+-------------------------------
+If the ARMv8.2-LVA optional feature is present, and we are running
+with a 64KB page size; then it is possible to use 52-bits of address
+space for both userspace and kernel addresses. However, any kernel
+binary that supports 52-bit must also be able to fall back to 48-bit
+at early boot time if the hardware feature is not present.
+
+This fallback mechanism necessitates the kernel .text to be in the
+higher addresses such that they are invariant to 48/52-bit VAs. Due
+to the kasan shadow being a fraction of the entire kernel VA space,
+the end of the kasan shadow must also be in the higher half of the
+kernel VA space for both 48/52-bit. (Switching from 48-bit to 52-bit,
+the end of the kasan shadow is invariant and dependent on ~0UL,
+whilst the start address will "grow" towards the lower addresses).
+
+In order to optimise phys_to_virt and virt_to_phys, the PAGE_OFFSET
+is kept constant at 0xFFF0000000000000 (corresponding to 52-bit),
+this obviates the need for an extra variable read. The physvirt
+offset and vmemmap offsets are computed at early boot to enable
+this logic.
+
+As a single binary will need to support both 48-bit and 52-bit VA
+spaces, the VMEMMAP must be sized large enough for 52-bit VAs and
+also must be sized large enought to accommodate a fixed PAGE_OFFSET.
+
+Most code in the kernel should not need to consider the VA_BITS, for
+code that does need to know the VA size the variables are
+defined as follows:
+
+VA_BITS                constant        the *maximum* VA space size
+
+VA_BITS_MIN    constant        the *minimum* VA space size
+
+vabits_actual  variable        the *actual* VA space size
+
+
+Maximum and minimum sizes can be useful to ensure that buffers are
+sized large enough or that addresses are positioned close enough for
+the "worst" case.
+
+52-bit userspace VAs
+--------------------
+To maintain compatibility with software that relies on the ARMv8.0
+VA space maximum size of 48-bits, the kernel will, by default,
+return virtual addresses to userspace from a 48-bit range.
+
+Software can "opt-in" to receiving VAs from a 52-bit space by
+specifying an mmap hint parameter that is larger than 48-bit.
+For example:
+    maybe_high_address = mmap(~0UL, size, prot, flags,...);
+
+It is also possible to build a debug kernel that returns addresses
+from a 52-bit space by enabling the following kernel config options:
+   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y
+
+Note that this option is only intended for debugging applications
+and should not be used in production.
diff --git a/Documentation/arm64/tagged-address-abi.rst b/Documentation/arm64/tagged-address-abi.rst
new file mode 100644 (file)
index 0000000..d4a85d5
--- /dev/null
@@ -0,0 +1,156 @@
+==========================
+AArch64 TAGGED ADDRESS ABI
+==========================
+
+Authors: Vincenzo Frascino <vincenzo.frascino@arm.com>
+         Catalin Marinas <catalin.marinas@arm.com>
+
+Date: 21 August 2019
+
+This document describes the usage and semantics of the Tagged Address
+ABI on AArch64 Linux.
+
+1. Introduction
+---------------
+
+On AArch64 the ``TCR_EL1.TBI0`` bit is set by default, allowing
+userspace (EL0) to perform memory accesses through 64-bit pointers with
+a non-zero top byte. This document describes the relaxation of the
+syscall ABI that allows userspace to pass certain tagged pointers to
+kernel syscalls.
+
+2. AArch64 Tagged Address ABI
+-----------------------------
+
+From the kernel syscall interface perspective and for the purposes of
+this document, a "valid tagged pointer" is a pointer with a potentially
+non-zero top-byte that references an address in the user process address
+space obtained in one of the following ways:
+
+- ``mmap()`` syscall where either:
+
+  - flags have the ``MAP_ANONYMOUS`` bit set or
+  - the file descriptor refers to a regular file (including those
+    returned by ``memfd_create()``) or ``/dev/zero``
+
+- ``brk()`` syscall (i.e. the heap area between the initial location of
+  the program break at process creation and its current location).
+
+- any memory mapped by the kernel in the address space of the process
+  during creation and with the same restrictions as for ``mmap()`` above
+  (e.g. data, bss, stack).
+
+The AArch64 Tagged Address ABI has two stages of relaxation depending
+how the user addresses are used by the kernel:
+
+1. User addresses not accessed by the kernel but used for address space
+   management (e.g. ``mmap()``, ``mprotect()``, ``madvise()``). The use
+   of valid tagged pointers in this context is always allowed.
+
+2. User addresses accessed by the kernel (e.g. ``write()``). This ABI
+   relaxation is disabled by default and the application thread needs to
+   explicitly enable it via ``prctl()`` as follows:
+
+   - ``PR_SET_TAGGED_ADDR_CTRL``: enable or disable the AArch64 Tagged
+     Address ABI for the calling thread.
+
+     The ``(unsigned int) arg2`` argument is a bit mask describing the
+     control mode used:
+
+     - ``PR_TAGGED_ADDR_ENABLE``: enable AArch64 Tagged Address ABI.
+       Default status is disabled.
+
+     Arguments ``arg3``, ``arg4``, and ``arg5`` must be 0.
+
+   - ``PR_GET_TAGGED_ADDR_CTRL``: get the status of the AArch64 Tagged
+     Address ABI for the calling thread.
+
+     Arguments ``arg2``, ``arg3``, ``arg4``, and ``arg5`` must be 0.
+
+   The ABI properties described above are thread-scoped, inherited on
+   clone() and fork() and cleared on exec().
+
+   Calling ``prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)``
+   returns ``-EINVAL`` if the AArch64 Tagged Address ABI is globally
+   disabled by ``sysctl abi.tagged_addr_disabled=1``. The default
+   ``sysctl abi.tagged_addr_disabled`` configuration is 0.
+
+When the AArch64 Tagged Address ABI is enabled for a thread, the
+following behaviours are guaranteed:
+
+- All syscalls except the cases mentioned in section 3 can accept any
+  valid tagged pointer.
+
+- The syscall behaviour is undefined for invalid tagged pointers: it may
+  result in an error code being returned, a (fatal) signal being raised,
+  or other modes of failure.
+
+- The syscall behaviour for a valid tagged pointer is the same as for
+  the corresponding untagged pointer.
+
+
+A definition of the meaning of tagged pointers on AArch64 can be found
+in Documentation/arm64/tagged-pointers.rst.
+
+3. AArch64 Tagged Address ABI Exceptions
+-----------------------------------------
+
+The following system call parameters must be untagged regardless of the
+ABI relaxation:
+
+- ``prctl()`` other than pointers to user data either passed directly or
+  indirectly as arguments to be accessed by the kernel.
+
+- ``ioctl()`` other than pointers to user data either passed directly or
+  indirectly as arguments to be accessed by the kernel.
+
+- ``shmat()`` and ``shmdt()``.
+
+Any attempt to use non-zero tagged pointers may result in an error code
+being returned, a (fatal) signal being raised, or other modes of
+failure.
+
+4. Example of correct usage
+---------------------------
+.. code-block:: c
+
+   #include <stdlib.h>
+   #include <string.h>
+   #include <unistd.h>
+   #include <sys/mman.h>
+   #include <sys/prctl.h>
+   
+   #define PR_SET_TAGGED_ADDR_CTRL     55
+   #define PR_TAGGED_ADDR_ENABLE       (1UL << 0)
+   
+   #define TAG_SHIFT           56
+   
+   int main(void)
+   {
+       int tbi_enabled = 0;
+       unsigned long tag = 0;
+       char *ptr;
+   
+       /* check/enable the tagged address ABI */
+       if (!prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0))
+               tbi_enabled = 1;
+   
+       /* memory allocation */
+       ptr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
+                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if (ptr == MAP_FAILED)
+               return 1;
+   
+       /* set a non-zero tag if the ABI is available */
+       if (tbi_enabled)
+               tag = rand() & 0xff;
+       ptr = (char *)((unsigned long)ptr | (tag << TAG_SHIFT));
+   
+       /* memory access to a tagged address */
+       strcpy(ptr, "tagged pointer\n");
+   
+       /* syscall with a tagged pointer */
+       write(1, ptr, strlen(ptr));
+   
+       return 0;
+   }
index 2acdec3..eab4323 100644 (file)
@@ -20,7 +20,9 @@ Passing tagged addresses to the kernel
 --------------------------------------
 
 All interpretation of userspace memory addresses by the kernel assumes
-an address tag of 0x00.
+an address tag of 0x00, unless the application enables the AArch64
+Tagged Address ABI explicitly
+(Documentation/arm64/tagged-address-abi.rst).
 
 This includes, but is not limited to, addresses found in:
 
@@ -33,13 +35,15 @@ This includes, but is not limited to, addresses found in:
  - the frame pointer (x29) and frame records, e.g. when interpreting
    them to generate a backtrace or call graph.
 
-Using non-zero address tags in any of these locations may result in an
-error code being returned, a (fatal) signal being raised, or other modes
-of failure.
+Using non-zero address tags in any of these locations when the
+userspace application did not enable the AArch64 Tagged Address ABI may
+result in an error code being returned, a (fatal) signal being raised,
+or other modes of failure.
 
-For these reasons, passing non-zero address tags to the kernel via
-system calls is forbidden, and using a non-zero address tag for sp is
-strongly discouraged.
+For these reasons, when the AArch64 Tagged Address ABI is disabled,
+passing non-zero address tags to the kernel via system calls is
+forbidden, and using a non-zero address tag for sp is strongly
+discouraged.
 
 Programs maintaining a frame pointer and frame records that use non-zero
 address tags may suffer impaired or inaccurate debug and profiling
@@ -59,6 +63,9 @@ be preserved.
 The architecture prevents the use of a tagged PC, so the upper byte will
 be set to a sign-extension of bit 55 on exception return.
 
+This behaviour is maintained when the AArch64 Tagged Address ABI is
+enabled.
+
 
 Other considerations
 --------------------
index 6b0dfd5..5138a2f 100644 (file)
@@ -19,7 +19,9 @@ quiet_cmd_mk_schema = SCHEMA  $@
 
 DT_DOCS = $(shell \
        cd $(srctree)/$(src) && \
-       find * \( -name '*.yaml' ! -name $(DT_TMP_SCHEMA) \) \
+       find * \( -name '*.yaml' ! \
+               -name $(DT_TMP_SCHEMA) ! \
+               -name '*.example.dt.yaml' \) \
        )
 
 DT_SCHEMA_FILES ?= $(addprefix $(src)/,$(DT_DOCS))
diff --git a/Documentation/devicetree/bindings/arm/topology.txt b/Documentation/devicetree/bindings/arm/topology.txt
deleted file mode 100644 (file)
index b0d80c0..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-===========================================
-ARM topology binding description
-===========================================
-
-===========================================
-1 - Introduction
-===========================================
-
-In an ARM system, the hierarchy of CPUs is defined through three entities that
-are used to describe the layout of physical CPUs in the system:
-
-- cluster
-- core
-- thread
-
-The cpu nodes (bindings defined in [1]) represent the devices that
-correspond to physical CPUs and are to be mapped to the hierarchy levels.
-
-The bottom hierarchy level sits at core or thread level depending on whether
-symmetric multi-threading (SMT) is supported or not.
-
-For instance in a system where CPUs support SMT, "cpu" nodes represent all
-threads existing in the system and map to the hierarchy level "thread" above.
-In systems where SMT is not supported "cpu" nodes represent all cores present
-in the system and map to the hierarchy level "core" above.
-
-ARM topology bindings allow one to associate cpu nodes with hierarchical groups
-corresponding to the system hierarchy; syntactically they are defined as device
-tree nodes.
-
-The remainder of this document provides the topology bindings for ARM, based
-on the Devicetree Specification, available from:
-
-https://www.devicetree.org/specifications/
-
-If not stated otherwise, whenever a reference to a cpu node phandle is made its
-value must point to a cpu node compliant with the cpu node bindings as
-documented in [1].
-A topology description containing phandles to cpu nodes that are not compliant
-with bindings standardized in [1] is therefore considered invalid.
-
-===========================================
-2 - cpu-map node
-===========================================
-
-The ARM CPU topology is defined within the cpu-map node, which is a direct
-child of the cpus node and provides a container where the actual topology
-nodes are listed.
-
-- cpu-map node
-
-       Usage: Optional - On ARM SMP systems provide CPUs topology to the OS.
-                         ARM uniprocessor systems do not require a topology
-                         description and therefore should not define a
-                         cpu-map node.
-
-       Description: The cpu-map node is just a container node where its
-                    subnodes describe the CPU topology.
-
-       Node name must be "cpu-map".
-
-       The cpu-map node's parent node must be the cpus node.
-
-       The cpu-map node's child nodes can be:
-
-       - one or more cluster nodes
-
-       Any other configuration is considered invalid.
-
-The cpu-map node can only contain three types of child nodes:
-
-- cluster node
-- core node
-- thread node
-
-whose bindings are described in paragraph 3.
-
-The nodes describing the CPU topology (cluster/core/thread) can only
-be defined within the cpu-map node and every core/thread in the system
-must be defined within the topology.  Any other configuration is
-invalid and therefore must be ignored.
-
-===========================================
-2.1 - cpu-map child nodes naming convention
-===========================================
-
-cpu-map child nodes must follow a naming convention where the node name
-must be "clusterN", "coreN", "threadN" depending on the node type (ie
-cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes which
-are siblings within a single common parent node must be given a unique and
-sequential N value, starting from 0).
-cpu-map child nodes which do not share a common parent node can have the same
-name (ie same number N as other cpu-map child nodes at different device tree
-levels) since name uniqueness will be guaranteed by the device tree hierarchy.
-
-===========================================
-3 - cluster/core/thread node bindings
-===========================================
-
-Bindings for cluster/cpu/thread nodes are defined as follows:
-
-- cluster node
-
-        Description: must be declared within a cpu-map node, one node
-                     per cluster. A system can contain several layers of
-                     clustering and cluster nodes can be contained in parent
-                     cluster nodes.
-
-       The cluster node name must be "clusterN" as described in 2.1 above.
-       A cluster node can not be a leaf node.
-
-       A cluster node's child nodes must be:
-
-       - one or more cluster nodes; or
-       - one or more core nodes
-
-       Any other configuration is considered invalid.
-
-- core node
-
-       Description: must be declared in a cluster node, one node per core in
-                    the cluster. If the system does not support SMT, core
-                    nodes are leaf nodes, otherwise they become containers of
-                    thread nodes.
-
-       The core node name must be "coreN" as described in 2.1 above.
-
-       A core node must be a leaf node if SMT is not supported.
-
-       Properties for core nodes that are leaf nodes:
-
-       - cpu
-               Usage: required
-               Value type: <phandle>
-               Definition: a phandle to the cpu node that corresponds to the
-                           core node.
-
-       If a core node is not a leaf node (CPUs supporting SMT) a core node's
-       child nodes can be:
-
-       - one or more thread nodes
-
-       Any other configuration is considered invalid.
-
-- thread node
-
-       Description: must be declared in a core node, one node per thread
-                    in the core if the system supports SMT. Thread nodes are
-                    always leaf nodes in the device tree.
-
-       The thread node name must be "threadN" as described in 2.1 above.
-
-       A thread node must be a leaf node.
-
-       A thread node must contain the following property:
-
-       - cpu
-               Usage: required
-               Value type: <phandle>
-               Definition: a phandle to the cpu node that corresponds to
-                           the thread node.
-
-===========================================
-4 - Example dts
-===========================================
-
-Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters):
-
-cpus {
-       #size-cells = <0>;
-       #address-cells = <2>;
-
-       cpu-map {
-               cluster0 {
-                       cluster0 {
-                               core0 {
-                                       thread0 {
-                                               cpu = <&CPU0>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU1>;
-                                       };
-                               };
-
-                               core1 {
-                                       thread0 {
-                                               cpu = <&CPU2>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU3>;
-                                       };
-                               };
-                       };
-
-                       cluster1 {
-                               core0 {
-                                       thread0 {
-                                               cpu = <&CPU4>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU5>;
-                                       };
-                               };
-
-                               core1 {
-                                       thread0 {
-                                               cpu = <&CPU6>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU7>;
-                                       };
-                               };
-                       };
-               };
-
-               cluster1 {
-                       cluster0 {
-                               core0 {
-                                       thread0 {
-                                               cpu = <&CPU8>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU9>;
-                                       };
-                               };
-                               core1 {
-                                       thread0 {
-                                               cpu = <&CPU10>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU11>;
-                                       };
-                               };
-                       };
-
-                       cluster1 {
-                               core0 {
-                                       thread0 {
-                                               cpu = <&CPU12>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU13>;
-                                       };
-                               };
-                               core1 {
-                                       thread0 {
-                                               cpu = <&CPU14>;
-                                       };
-                                       thread1 {
-                                               cpu = <&CPU15>;
-                                       };
-                               };
-                       };
-               };
-       };
-
-       CPU0: cpu@0 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x0>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU1: cpu@1 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x1>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU2: cpu@100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x100>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU3: cpu@101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x101>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU4: cpu@10000 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x10000>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU5: cpu@10001 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x10001>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU6: cpu@10100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x10100>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU7: cpu@10101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x0 0x10101>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU8: cpu@100000000 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x0>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU9: cpu@100000001 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x1>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU10: cpu@100000100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x100>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU11: cpu@100000101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x101>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU12: cpu@100010000 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x10000>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU13: cpu@100010001 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x10001>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU14: cpu@100010100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x10100>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-
-       CPU15: cpu@100010101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a57";
-               reg = <0x1 0x10101>;
-               enable-method = "spin-table";
-               cpu-release-addr = <0 0x20000000>;
-       };
-};
-
-Example 2 (ARM 32-bit, dual-cluster, 8-cpu system, no SMT):
-
-cpus {
-       #size-cells = <0>;
-       #address-cells = <1>;
-
-       cpu-map {
-               cluster0 {
-                       core0 {
-                               cpu = <&CPU0>;
-                       };
-                       core1 {
-                               cpu = <&CPU1>;
-                       };
-                       core2 {
-                               cpu = <&CPU2>;
-                       };
-                       core3 {
-                               cpu = <&CPU3>;
-                       };
-               };
-
-               cluster1 {
-                       core0 {
-                               cpu = <&CPU4>;
-                       };
-                       core1 {
-                               cpu = <&CPU5>;
-                       };
-                       core2 {
-                               cpu = <&CPU6>;
-                       };
-                       core3 {
-                               cpu = <&CPU7>;
-                       };
-               };
-       };
-
-       CPU0: cpu@0 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a15";
-               reg = <0x0>;
-       };
-
-       CPU1: cpu@1 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a15";
-               reg = <0x1>;
-       };
-
-       CPU2: cpu@2 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a15";
-               reg = <0x2>;
-       };
-
-       CPU3: cpu@3 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a15";
-               reg = <0x3>;
-       };
-
-       CPU4: cpu@100 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a7";
-               reg = <0x100>;
-       };
-
-       CPU5: cpu@101 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a7";
-               reg = <0x101>;
-       };
-
-       CPU6: cpu@102 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a7";
-               reg = <0x102>;
-       };
-
-       CPU7: cpu@103 {
-               device_type = "cpu";
-               compatible = "arm,cortex-a7";
-               reg = <0x103>;
-       };
-};
-
-===============================================================================
-[1] ARM Linux kernel documentation
-    Documentation/devicetree/bindings/arm/cpus.yaml
diff --git a/Documentation/devicetree/bindings/cpu/cpu-topology.txt b/Documentation/devicetree/bindings/cpu/cpu-topology.txt
new file mode 100644 (file)
index 0000000..9991818
--- /dev/null
@@ -0,0 +1,553 @@
+===========================================
+CPU topology binding description
+===========================================
+
+===========================================
+1 - Introduction
+===========================================
+
+In a SMP system, the hierarchy of CPUs is defined through three entities that
+are used to describe the layout of physical CPUs in the system:
+
+- socket
+- cluster
+- core
+- thread
+
+The bottom hierarchy level sits at core or thread level depending on whether
+symmetric multi-threading (SMT) is supported or not.
+
+For instance in a system where CPUs support SMT, "cpu" nodes represent all
+threads existing in the system and map to the hierarchy level "thread" above.
+In systems where SMT is not supported "cpu" nodes represent all cores present
+in the system and map to the hierarchy level "core" above.
+
+CPU topology bindings allow one to associate cpu nodes with hierarchical groups
+corresponding to the system hierarchy; syntactically they are defined as device
+tree nodes.
+
+Currently, only ARM/RISC-V intend to use this cpu topology binding but it may be
+used for any other architecture as well.
+
+The cpu nodes, as per bindings defined in [4], represent the devices that
+correspond to physical CPUs and are to be mapped to the hierarchy levels.
+
+A topology description containing phandles to cpu nodes that are not compliant
+with bindings standardized in [4] is therefore considered invalid.
+
+===========================================
+2 - cpu-map node
+===========================================
+
+The ARM/RISC-V CPU topology is defined within the cpu-map node, which is a direct
+child of the cpus node and provides a container where the actual topology
+nodes are listed.
+
+- cpu-map node
+
+       Usage: Optional - On SMP systems provide CPUs topology to the OS.
+                         Uniprocessor systems do not require a topology
+                         description and therefore should not define a
+                         cpu-map node.
+
+       Description: The cpu-map node is just a container node where its
+                    subnodes describe the CPU topology.
+
+       Node name must be "cpu-map".
+
+       The cpu-map node's parent node must be the cpus node.
+
+       The cpu-map node's child nodes can be:
+
+       - one or more cluster nodes or
+       - one or more socket nodes in a multi-socket system
+
+       Any other configuration is considered invalid.
+
+The cpu-map node can only contain 4 types of child nodes:
+
+- socket node
+- cluster node
+- core node
+- thread node
+
+whose bindings are described in paragraph 3.
+
+The nodes describing the CPU topology (socket/cluster/core/thread) can
+only be defined within the cpu-map node and every core/thread in the
+system must be defined within the topology.  Any other configuration is
+invalid and therefore must be ignored.
+
+===========================================
+2.1 - cpu-map child nodes naming convention
+===========================================
+
+cpu-map child nodes must follow a naming convention where the node name
+must be "socketN", "clusterN", "coreN", "threadN" depending on the node type
+(ie socket/cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes
+which are siblings within a single common parent node must be given a unique and
+sequential N value, starting from 0).
+cpu-map child nodes which do not share a common parent node can have the same
+name (ie same number N as other cpu-map child nodes at different device tree
+levels) since name uniqueness will be guaranteed by the device tree hierarchy.
+
+===========================================
+3 - socket/cluster/core/thread node bindings
+===========================================
+
+Bindings for socket/cluster/cpu/thread nodes are defined as follows:
+
+- socket node
+
+        Description: must be declared within a cpu-map node, one node
+                     per physical socket in the system. A system can
+                     contain single or multiple physical socket.
+                     The association of sockets and NUMA nodes is beyond
+                     the scope of this bindings, please refer [2] for
+                     NUMA bindings.
+
+       This node is optional for a single socket system.
+
+       The socket node name must be "socketN" as described in 2.1 above.
+       A socket node can not be a leaf node.
+
+       A socket node's child nodes must be one or more cluster nodes.
+
+       Any other configuration is considered invalid.
+
+- cluster node
+
+        Description: must be declared within a cpu-map node, one node
+                     per cluster. A system can contain several layers of
+                     clustering within a single physical socket and cluster
+                     nodes can be contained in parent cluster nodes.
+
+       The cluster node name must be "clusterN" as described in 2.1 above.
+       A cluster node can not be a leaf node.
+
+       A cluster node's child nodes must be:
+
+       - one or more cluster nodes; or
+       - one or more core nodes
+
+       Any other configuration is considered invalid.
+
+- core node
+
+       Description: must be declared in a cluster node, one node per core in
+                    the cluster. If the system does not support SMT, core
+                    nodes are leaf nodes, otherwise they become containers of
+                    thread nodes.
+
+       The core node name must be "coreN" as described in 2.1 above.
+
+       A core node must be a leaf node if SMT is not supported.
+
+       Properties for core nodes that are leaf nodes:
+
+       - cpu
+               Usage: required
+               Value type: <phandle>
+               Definition: a phandle to the cpu node that corresponds to the
+                           core node.
+
+       If a core node is not a leaf node (CPUs supporting SMT) a core node's
+       child nodes can be:
+
+       - one or more thread nodes
+
+       Any other configuration is considered invalid.
+
+- thread node
+
+       Description: must be declared in a core node, one node per thread
+                    in the core if the system supports SMT. Thread nodes are
+                    always leaf nodes in the device tree.
+
+       The thread node name must be "threadN" as described in 2.1 above.
+
+       A thread node must be a leaf node.
+
+       A thread node must contain the following property:
+
+       - cpu
+               Usage: required
+               Value type: <phandle>
+               Definition: a phandle to the cpu node that corresponds to
+                           the thread node.
+
+===========================================
+4 - Example dts
+===========================================
+
+Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters in a single
+physical socket):
+
+cpus {
+       #size-cells = <0>;
+       #address-cells = <2>;
+
+       cpu-map {
+               socket0 {
+                       cluster0 {
+                               cluster0 {
+                                       core0 {
+                                               thread0 {
+                                                       cpu = <&CPU0>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU1>;
+                                               };
+                                       };
+
+                                       core1 {
+                                               thread0 {
+                                                       cpu = <&CPU2>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU3>;
+                                               };
+                                       };
+                               };
+
+                               cluster1 {
+                                       core0 {
+                                               thread0 {
+                                                       cpu = <&CPU4>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU5>;
+                                               };
+                                       };
+
+                                       core1 {
+                                               thread0 {
+                                                       cpu = <&CPU6>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU7>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       cluster1 {
+                               cluster0 {
+                                       core0 {
+                                               thread0 {
+                                                       cpu = <&CPU8>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU9>;
+                                               };
+                                       };
+                                       core1 {
+                                               thread0 {
+                                                       cpu = <&CPU10>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU11>;
+                                               };
+                                       };
+                               };
+
+                               cluster1 {
+                                       core0 {
+                                               thread0 {
+                                                       cpu = <&CPU12>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU13>;
+                                               };
+                                       };
+                                       core1 {
+                                               thread0 {
+                                                       cpu = <&CPU14>;
+                                               };
+                                               thread1 {
+                                                       cpu = <&CPU15>;
+                                               };
+                                       };
+                               };
+                       };
+               };
+       };
+
+       CPU0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x0>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU1: cpu@1 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x1>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU2: cpu@100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x100>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU3: cpu@101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x101>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU4: cpu@10000 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x10000>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU5: cpu@10001 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x10001>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU6: cpu@10100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x10100>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU7: cpu@10101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x0 0x10101>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU8: cpu@100000000 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x0>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU9: cpu@100000001 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x1>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU10: cpu@100000100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x100>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU11: cpu@100000101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x101>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU12: cpu@100010000 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x10000>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU13: cpu@100010001 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x10001>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU14: cpu@100010100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x10100>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+
+       CPU15: cpu@100010101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a57";
+               reg = <0x1 0x10101>;
+               enable-method = "spin-table";
+               cpu-release-addr = <0 0x20000000>;
+       };
+};
+
+Example 2 (ARM 32-bit, dual-cluster, 8-cpu system, no SMT):
+
+cpus {
+       #size-cells = <0>;
+       #address-cells = <1>;
+
+       cpu-map {
+               cluster0 {
+                       core0 {
+                               cpu = <&CPU0>;
+                       };
+                       core1 {
+                               cpu = <&CPU1>;
+                       };
+                       core2 {
+                               cpu = <&CPU2>;
+                       };
+                       core3 {
+                               cpu = <&CPU3>;
+                       };
+               };
+
+               cluster1 {
+                       core0 {
+                               cpu = <&CPU4>;
+                       };
+                       core1 {
+                               cpu = <&CPU5>;
+                       };
+                       core2 {
+                               cpu = <&CPU6>;
+                       };
+                       core3 {
+                               cpu = <&CPU7>;
+                       };
+               };
+       };
+
+       CPU0: cpu@0 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a15";
+               reg = <0x0>;
+       };
+
+       CPU1: cpu@1 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a15";
+               reg = <0x1>;
+       };
+
+       CPU2: cpu@2 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a15";
+               reg = <0x2>;
+       };
+
+       CPU3: cpu@3 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a15";
+               reg = <0x3>;
+       };
+
+       CPU4: cpu@100 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x100>;
+       };
+
+       CPU5: cpu@101 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x101>;
+       };
+
+       CPU6: cpu@102 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x102>;
+       };
+
+       CPU7: cpu@103 {
+               device_type = "cpu";
+               compatible = "arm,cortex-a7";
+               reg = <0x103>;
+       };
+};
+
+Example 3: HiFive Unleashed (RISC-V 64 bit, 4 core system)
+
+{
+       #address-cells = <2>;
+       #size-cells = <2>;
+       compatible = "sifive,fu540g", "sifive,fu500";
+       model = "sifive,hifive-unleashed-a00";
+
+       ...
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu-map {
+                       socket0 {
+                               cluster0 {
+                                       core0 {
+                                               cpu = <&CPU1>;
+                                       };
+                                       core1 {
+                                               cpu = <&CPU2>;
+                                       };
+                                       core2 {
+                                               cpu0 = <&CPU2>;
+                                       };
+                                       core3 {
+                                               cpu0 = <&CPU3>;
+                                       };
+                               };
+                       };
+               };
+
+               CPU1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "sifive,rocket0", "riscv";
+                       reg = <0x1>;
+               }
+
+               CPU2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "sifive,rocket0", "riscv";
+                       reg = <0x2>;
+               }
+               CPU3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "sifive,rocket0", "riscv";
+                       reg = <0x3>;
+               }
+               CPU4: cpu@4 {
+                       device_type = "cpu";
+                       compatible = "sifive,rocket0", "riscv";
+                       reg = <0x4>;
+               }
+       }
+};
+===============================================================================
+[1] ARM Linux kernel documentation
+    Documentation/devicetree/bindings/arm/cpus.yaml
+[2] Devicetree NUMA binding description
+    Documentation/devicetree/bindings/numa.txt
+[3] RISC-V Linux kernel documentation
+    Documentation/devicetree/bindings/riscv/cpus.txt
+[4] https://www.devicetree.org/specifications/
index 7e9b586..b2033fc 100644 (file)
@@ -2,7 +2,8 @@ Aspeed GPIO controller Device Tree Bindings
 -------------------------------------------
 
 Required properties:
-- compatible           : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio"
+- compatible           : Either "aspeed,ast2400-gpio", "aspeed,ast2500-gpio",
+                                       or "aspeed,ast2600-gpio".
 
 - #gpio-cells          : Should be two
                          - First cell is the GPIO line number
@@ -17,7 +18,9 @@ Required properties:
 
 Optional properties:
 
-- clocks                : A phandle to the clock to use for debounce timings
+- clocks               : A phandle to the clock to use for debounce timings
+- ngpios               : Number of GPIOs controlled by this controller. Should be set
+                                 when there are multiple GPIO controllers on a SoC (ast2600).
 
 The gpio and interrupt properties are further described in their respective
 bindings documentation:
index bc6b4b6..cd91d61 100644 (file)
@@ -6,6 +6,7 @@ Required Properties:
                                                66AK2E SoCs
                        "ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
                        "ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654
+                       "ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs
 
 - reg: Physical base address of the controller and the size of memory mapped
        registers.
index 69d4616..cd28e93 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible : Should be "fsl,<soc>-gpio"
   The following <soc>s are known to be supported:
        mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq,
-       ls1021a, ls1043a, ls2080a.
+       ls1021a, ls1043a, ls2080a, ls1028a, ls1088a.
 - reg : Address and length of the register set for the device
 - interrupts : Should be the port interrupt shared by all 32 pins.
 - #gpio-cells : Should be two.  The first cell is the pin number and
@@ -37,3 +37,17 @@ gpio0: gpio@2300000 {
        interrupt-controller;
        #interrupt-cells = <2>;
 };
+
+
+Example of gpio-controller node for a ls1028a/ls1088a SoC:
+
+gpio1: gpio@2300000 {
+       compatible = "fsl,ls1028a-gpio", "fsl,ls1088a-gpio", "fsl,qoriq-gpio";
+       reg = <0x0 0x2300000 0x0 0x10000>;
+       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+       gpio-controller;
+       #gpio-cells = <2>;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       little-endian;
+};
diff --git a/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
new file mode 100644 (file)
index 0000000..d4d8391
--- /dev/null
@@ -0,0 +1,45 @@
+Aspeed SGPIO controller Device Tree Bindings
+--------------------------------------------
+
+This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80 full
+featured Serial GPIOs. Each of the Serial GPIO pins can be programmed to
+support the following options:
+- Support interrupt option for each input port and various interrupt
+  sensitivity option (level-high, level-low, edge-high, edge-low)
+- Support reset tolerance option for each output port
+- Directly connected to APB bus and its shift clock is from APB bus clock
+  divided by a programmable value.
+- Co-work with external signal-chained TTL components (74LV165/74LV595)
+
+Required properties:
+
+- compatible : Should be one of
+  "aspeed,ast2400-sgpio", "aspeed,ast2500-sgpio"
+- #gpio-cells : Should be 2, see gpio.txt
+- reg : Address and length of the register set for the device
+- gpio-controller : Marks the device node as a GPIO controller
+- interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
+- interrupt-controller : Mark the GPIO controller as an interrupt-controller
+- ngpios : number of GPIO lines, see gpio.txt
+  (should be multiple of 8, up to 80 pins)
+- clocks : A phandle to the APB clock for SGPM clock division
+- bus-frequency : SGPM CLK frequency
+
+The sgpio and interrupt properties are further described in their respective
+bindings documentation:
+
+- Documentation/devicetree/bindings/gpio/gpio.txt
+- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+  Example:
+       sgpio: sgpio@1e780200 {
+               #gpio-cells = <2>;
+               compatible = "aspeed,ast2500-sgpio";
+               gpio-controller;
+               interrupts = <40>;
+               reg = <0x1e780200 0x0100>;
+               clocks = <&syscon ASPEED_CLK_APB>;
+               interrupt-controller;
+               ngpios = <8>;
+               bus-frequency = <12000000>;
+       };
diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
deleted file mode 100644 (file)
index 918a507..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-ADS1015 (I2C)
-
-This device is a 12-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-For configuration all possible combinations are mapped to 8 channels:
-  0: Voltage over AIN0 and AIN1.
-  1: Voltage over AIN0 and AIN3.
-  2: Voltage over AIN1 and AIN3.
-  3: Voltage over AIN2 and AIN3.
-  4: Voltage over AIN0 and GND.
-  5: Voltage over AIN1 and GND.
-  6: Voltage over AIN2 and GND.
-  7: Voltage over AIN3 and GND.
-
-Each channel can be configured individually:
- - pga is the programmable gain amplifier (values are full scale)
-    0: +/- 6.144 V
-    1: +/- 4.096 V
-    2: +/- 2.048 V (default)
-    3: +/- 1.024 V
-    4: +/- 0.512 V
-    5: +/- 0.256 V
- - data_rate in samples per second
-    0: 128
-    1: 250
-    2: 490
-    3: 920
-    4: 1600 (default)
-    5: 2400
-    6: 3300
-
-1) The /ads1015 node
-
-  Required properties:
-
-   - compatible : must be "ti,ads1015"
-   - reg : I2C bus address of the device
-   - #address-cells : must be <1>
-   - #size-cells : must be <0>
-
-  The node contains child nodes for each channel that the platform uses.
-
-  Example ADS1015 node:
-
-    ads1015@49 {
-           compatible = "ti,ads1015";
-           reg = <0x49>;
-           #address-cells = <1>;
-           #size-cells = <0>;
-
-           [ child node definitions... ]
-    }
-
-2) channel nodes
-
-  Required properties:
-
-   - reg : the channel number
-
-  Optional properties:
-
-   - ti,gain : the programmable gain amplifier setting
-   - ti,datarate : the converter data rate
-
-  Example ADS1015 channel node:
-
-    channel@4 {
-           reg = <4>;
-           ti,gain = <3>;
-           ti,datarate = <5>;
-    };
diff --git a/Documentation/devicetree/bindings/hwmon/as370.txt b/Documentation/devicetree/bindings/hwmon/as370.txt
new file mode 100644 (file)
index 0000000..d102fe7
--- /dev/null
@@ -0,0 +1,11 @@
+Bindings for Synaptics AS370 PVT sensors
+
+Required properties:
+- compatible : "syna,as370-hwmon"
+- reg        : address and length of the register set.
+
+Example:
+       hwmon@ea0810 {
+               compatible = "syna,as370-hwmon";
+               reg = <0xea0810 0xc>;
+       };
index f68a0a6..1036f65 100644 (file)
@@ -1,8 +1,10 @@
-Device-tree bindings for IBM Common Form Factor Power Supply Version 1
-----------------------------------------------------------------------
+Device-tree bindings for IBM Common Form Factor Power Supply Versions 1 and 2
+-----------------------------------------------------------------------------
 
 Required properties:
- - compatible = "ibm,cffps1";
+ - compatible                          : Must be one of the following:
+                                               "ibm,cffps1"
+                                               "ibm,cffps2"
  - reg = < I2C bus address >;          : Address of the power supply on the
                                          I2C bus.
 
index 586b5ed..2736167 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
                "maxim,max31725",
                "maxim,max31726",
                "maxim,mcp980x",
+               "nxp,pct2075",
                "st,stds75",
                "st,stlm75",
                "microchip,tcn75",
diff --git a/Documentation/devicetree/bindings/iio/adc/ads1015.txt b/Documentation/devicetree/bindings/iio/adc/ads1015.txt
new file mode 100644 (file)
index 0000000..918a507
--- /dev/null
@@ -0,0 +1,73 @@
+ADS1015 (I2C)
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+For configuration all possible combinations are mapped to 8 channels:
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured individually:
+ - pga is the programmable gain amplifier (values are full scale)
+    0: +/- 6.144 V
+    1: +/- 4.096 V
+    2: +/- 2.048 V (default)
+    3: +/- 1.024 V
+    4: +/- 0.512 V
+    5: +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600 (default)
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C bus address of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+           compatible = "ti,ads1015";
+           reg = <0x49>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+
+           [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter data rate
+
+  Example ADS1015 channel node:
+
+    channel@4 {
+           reg = <4>;
+           ti,gain = <3>;
+           ti,datarate = <5>;
+    };
index 09fc02b..a5c1db9 100644 (file)
@@ -1,20 +1,30 @@
 * ARC-HS Interrupt Distribution Unit
 
-  This optional 2nd level interrupt controller can be used in SMP configurations for
-  dynamic IRQ routing, load balancing of common/external IRQs towards core intc.
+  This optional 2nd level interrupt controller can be used in SMP configurations
+  for dynamic IRQ routing, load balancing of common/external IRQs towards core
+  intc.
 
 Properties:
 
 - compatible: "snps,archs-idu-intc"
 - interrupt-controller: This is an interrupt controller.
-- #interrupt-cells: Must be <1>.
-
-  Value of the cell specifies the "common" IRQ from peripheral to IDU. Number N
-  of the particular interrupt line of IDU corresponds to the line N+24 of the
-  core interrupt controller.
-
-  intc accessed via the special ARC AUX register interface, hence "reg" property
-  is not specified.
+- #interrupt-cells: Must be <1> or <2>.
+
+  Value of the first cell specifies the "common" IRQ from peripheral to IDU.
+  Number N of the particular interrupt line of IDU corresponds to the line N+24
+  of the core interrupt controller.
+
+  The (optional) second cell specifies any of the following flags:
+    - bits[3:0] trigger type and level flags
+        1 = low-to-high edge triggered
+        2 = NOT SUPPORTED (high-to-low edge triggered)
+        4 = active high level-sensitive <<< DEFAULT
+        8 = NOT SUPPORTED (active low level-sensitive)
+  When no second cell is specified, the interrupt is assumed to be level
+  sensitive.
+
+  The interrupt controller is accessed via the special ARC AUX register
+  interface, hence "reg" property is not specified.
 
 Example:
        core_intc: core-interrupt-controller {
index 6922db5..ce59a50 100644 (file)
@@ -11,10 +11,23 @@ ARM Short-Descriptor translation table format for address translation.
                |
               m4u (Multimedia Memory Management Unit)
                |
+          +--------+
+          |        |
+      gals0-rx   gals1-rx    (Global Async Local Sync rx)
+          |        |
+          |        |
+      gals0-tx   gals1-tx    (Global Async Local Sync tx)
+          |        |          Some SoCs may have GALS.
+          +--------+
+               |
            SMI Common(Smart Multimedia Interface Common)
                |
        +----------------+-------
        |                |
+       |             gals-rx        There may be GALS in some larbs.
+       |                |
+       |                |
+       |             gals-tx
        |                |
    SMI larb0        SMI larb1   ... SoCs have several SMI local arbiter(larb).
    (display)         (vdec)
@@ -36,6 +49,10 @@ each local arbiter.
 like display, video decode, and camera. And there are different ports
 in each larb. Take a example, There are many ports like MC, PP, VLD in the
 video decode local arbiter, all these ports are according to the video HW.
+  In some SoCs, there may be a GALS(Global Async Local Sync) module between
+smi-common and m4u, and additional GALS module between smi-larb and
+smi-common. GALS can been seen as a "asynchronous fifo" which could help
+synchronize for the modules in different clock frequency.
 
 Required properties:
 - compatible : must be one of the following string:
@@ -44,18 +61,25 @@ Required properties:
        "mediatek,mt7623-m4u", "mediatek,mt2701-m4u" for mt7623 which uses
                                                     generation one m4u HW.
        "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW.
+       "mediatek,mt8183-m4u" for mt8183 which uses generation two m4u HW.
 - reg : m4u register base and size.
 - interrupts : the interrupt of m4u.
 - clocks : must contain one entry for each clock-names.
-- clock-names : must be "bclk", It is the block clock of m4u.
+- clock-names : Only 1 optional clock:
+  - "bclk": the block clock of m4u.
+  Here is the list which require this "bclk":
+  - mt2701, mt2712, mt7623 and mt8173.
+  Note that m4u use the EMI clock which always has been enabled before kernel
+  if there is no this "bclk".
 - mediatek,larbs : List of phandle to the local arbiters in the current Socs.
        Refer to bindings/memory-controllers/mediatek,smi-larb.txt. It must sort
        according to the local arbiter index, like larb0, larb1, larb2...
 - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
        Specifies the mtk_m4u_id as defined in
        dt-binding/memory/mt2701-larb-port.h for mt2701, mt7623
-       dt-binding/memory/mt2712-larb-port.h for mt2712, and
-       dt-binding/memory/mt8173-larb-port.h for mt8173.
+       dt-binding/memory/mt2712-larb-port.h for mt2712,
+       dt-binding/memory/mt8173-larb-port.h for mt8173, and
+       dt-binding/memory/mt8183-larb-port.h for mt8183.
 
 Example:
        iommu: iommu@10205000 {
index e937ddd..b478ade 100644 (file)
@@ -2,9 +2,10 @@ SMI (Smart Multimedia Interface) Common
 
 The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
 
-Mediatek SMI have two generations of HW architecture, mt2712 and mt8173 use
-the second generation of SMI HW while mt2701 uses the first generation HW of
-SMI.
+Mediatek SMI have two generations of HW architecture, here is the list
+which generation the SoCs use:
+generation 1: mt2701 and mt7623.
+generation 2: mt2712, mt8173 and mt8183.
 
 There's slight differences between the two SMI, for generation 2, the
 register which control the iommu port is at each larb's register base. But
@@ -19,6 +20,7 @@ Required properties:
        "mediatek,mt2712-smi-common"
        "mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common"
        "mediatek,mt8173-smi-common"
+       "mediatek,mt8183-smi-common"
 - reg : the register and size of the SMI block.
 - power-domains : a phandle to the power domain of this local arbiter.
 - clocks : Must contain an entry for each entry in clock-names.
@@ -30,6 +32,10 @@ Required properties:
            They may be the same if both source clocks are the same.
   - "async" : asynchronous clock, it help transform the smi clock into the emi
              clock domain, this clock is only needed by generation 1 smi HW.
+  and these 2 option clocks for generation 2 smi HW:
+  - "gals0": the path0 clock of GALS(Global Async Local Sync).
+  - "gals1": the path1 clock of GALS(Global Async Local Sync).
+  Here is the list which has this GALS: mt8183.
 
 Example:
        smi_common: smi@14022000 {
index 94eddca..4b369b3 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
                "mediatek,mt2712-smi-larb"
                "mediatek,mt7623-smi-larb", "mediatek,mt2701-smi-larb"
                "mediatek,mt8173-smi-larb"
+               "mediatek,mt8183-smi-larb"
 - reg : the register and size of this local arbiter.
 - mediatek,smi : a phandle to the smi_common node.
 - power-domains : a phandle to the power domain of this local arbiter.
@@ -16,6 +17,9 @@ Required properties:
   - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
            the register.
   - "smi" : It's the clock for transfer data and command.
+  and this optional clock name:
+  - "gals": the clock for GALS(Global Async Local Sync).
+  Here is the list which has this GALS: mt8183.
 
 Required property for mt2701, mt2712 and mt7623:
 - mediatek,larb-id :the hardware id of this larb.
index 4ac21ce..113e7ac 100644 (file)
@@ -12,6 +12,7 @@ Required properties:
   - "microchip,ksz8565"
   - "microchip,ksz9893"
   - "microchip,ksz9563"
+  - "microchip,ksz8563"
 
 Optional properties:
 
index 2d41fb9..5b88fae 100644 (file)
@@ -7,18 +7,6 @@ Required properties:
 - phy-mode : See ethernet.txt file in the same directory
 
 Optional properties:
-- phy-reset-gpios : Should specify the gpio for phy reset
-- phy-reset-duration : Reset duration in milliseconds.  Should present
-  only if property "phy-reset-gpios" is available.  Missing the property
-  will have the duration be 1 millisecond.  Numbers greater than 1000 are
-  invalid and 1 millisecond will be used instead.
-- phy-reset-active-high : If present then the reset sequence using the GPIO
-  specified in the "phy-reset-gpios" property is reversed (H=reset state,
-  L=operation state).
-- phy-reset-post-delay : Post reset delay in milliseconds. If present then
-  a delay of phy-reset-post-delay milliseconds will be observed after the
-  phy-reset-gpios has been toggled. Can be omitted thus no delay is
-  observed. Delay is in range of 1ms to 1000ms. Other delays are invalid.
 - phy-supply : regulator that powers the Ethernet PHY.
 - phy-handle : phandle to the PHY device connected to this device.
 - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
@@ -47,11 +35,27 @@ Optional properties:
   For imx6sx, "int0" handles all 3 queues and ENET_MII. "pps" is for the pulse
   per second interrupt associated with 1588 precision time protocol(PTP).
 
-
 Optional subnodes:
 - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
   according to phy.txt in the same directory
 
+Deprecated optional properties:
+       To avoid these, create a phy node according to phy.txt in the same
+       directory, and point the fec's "phy-handle" property to it. Then use
+       the phy's reset binding, again described by phy.txt.
+- phy-reset-gpios : Should specify the gpio for phy reset
+- phy-reset-duration : Reset duration in milliseconds.  Should present
+  only if property "phy-reset-gpios" is available.  Missing the property
+  will have the duration be 1 millisecond.  Numbers greater than 1000 are
+  invalid and 1 millisecond will be used instead.
+- phy-reset-active-high : If present then the reset sequence using the GPIO
+  specified in the "phy-reset-gpios" property is reversed (H=reset state,
+  L=operation state).
+- phy-reset-post-delay : Post reset delay in milliseconds. If present then
+  a delay of phy-reset-post-delay milliseconds will be observed after the
+  phy-reset-gpios has been toggled. Can be omitted thus no delay is
+  observed. Delay is in range of 1ms to 1000ms. Other delays are invalid.
+
 Example:
 
 ethernet@83fec000 {
index 63c73fa..0b61a90 100644 (file)
@@ -15,10 +15,10 @@ Required properties:
   Use "atmel,sama5d4-gem" for the GEM IP (10/100) available on Atmel sama5d4 SoCs.
   Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
   Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
-  Use "sifive,fu540-macb" for SiFive FU540-C000 SoC.
+  Use "sifive,fu540-c000-gem" for SiFive FU540-C000 SoC.
   Or the generic form: "cdns,emac".
 - reg: Address and length of the register set for the device
-       For "sifive,fu540-macb", second range is required to specify the
+       For "sifive,fu540-c000-gem", second range is required to specify the
        address and length of the registers for GEMGXL Management block.
 - interrupts: Should contain macb interrupt
 - phy-mode: See ethernet.txt file in the same directory.
index 91d3e78..400df2d 100644 (file)
@@ -37,7 +37,8 @@ properties:
   hwlocks: true
 
   st,syscfg:
-    $ref: "/schemas/types.yaml#/definitions/phandle-array"
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
     description: Should be phandle/offset/mask
     items:
       - description: Phandle to the syscon node which includes IRQ mux selection.
index 3ae9f10..b9f58e4 100644 (file)
@@ -34,6 +34,9 @@ Optional input supply properties:
   - inl67-supply: The input supply for LDO_REG3 and LDO_REG4
 
 Any standard regulator properties can be used to configure the single regulator.
+regulator-initial-mode, regulator-allowed-modes and regulator-mode could be specified
+for act8865 using mode values from dt-bindings/regulator/active-semi,8865-regulator.h
+file.
 
 The valid names for regulators are:
        - for act8846:
@@ -47,6 +50,8 @@ The valid names for regulators are:
 Example:
 --------
 
+#include <dt-bindings/regulator/active-semi,8865-regulator.h>
+
                i2c1: i2c@f0018000 {
                        pmic: act8865@5b {
                                compatible = "active-semi,act8865";
@@ -65,9 +70,19 @@ Example:
                                                regulator-name = "VCC_1V2";
                                                regulator-min-microvolt = <1100000>;
                                                regulator-max-microvolt = <1300000>;
-                                               regulator-suspend-mem-microvolt = <1150000>;
-                                               regulator-suspend-standby-microvolt = <1150000>;
                                                regulator-always-on;
+
+                                               regulator-allowed-modes = <ACT8865_REGULATOR_MODE_FIXED>,
+                                                                         <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               regulator-initial-mode = <ACT8865_REGULATOR_MODE_FIXED>;
+
+                                               regulator-state-mem {
+                                                       regulator-on-in-suspend;
+                                                       regulator-suspend-min-microvolt = <1150000>;
+                                                       regulator-suspend-max-microvolt = <1150000>;
+                                                       regulator-changeable-in-suspend;
+                                                       regulator-mode = <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               };
                                        };
 
                                        vcc_3v3_reg: DCDC_REG3 {
@@ -82,6 +97,14 @@ Example:
                                                regulator-min-microvolt = <3300000>;
                                                regulator-max-microvolt = <3300000>;
                                                regulator-always-on;
+
+                                               regulator-allowed-modes = <ACT8865_REGULATOR_MODE_NORMAL>,
+                                                                         <ACT8865_REGULATOR_MODE_LOWPOWER>;
+                                               regulator-initial-mode = <ACT8865_REGULATOR_MODE_NORMAL>;
+
+                                               regulator-state-mem {
+                                                       regulator-off-in-suspend;
+                                               };
                                        };
 
                                        vddfuse_reg: LDO_REG2 {
index a650b45..a78150c 100644 (file)
@@ -19,9 +19,19 @@ description:
 allOf:
   - $ref: "regulator.yaml#"
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: regulator-fixed-clock
+  required:
+    - clocks
+
 properties:
   compatible:
-    const: regulator-fixed
+    enum:
+      - const: regulator-fixed
+      - const: regulator-fixed-clock
 
   regulator-name: true
 
@@ -29,6 +39,13 @@ properties:
     description: gpio to use for enable control
     maxItems: 1
 
+  clocks:
+    description:
+      clock to use for enable control. This binding is only available if
+      the compatible is chosen to regulator-fixed-clock. The clock binding
+      is mandatory if compatible is chosen to regulator-fixed-clock.
+    maxItems: 1
+
   startup-delay-us:
     description: startup time in microseconds
     $ref: /schemas/types.yaml#/definitions/uint32
diff --git a/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6358-regulator.txt
new file mode 100644 (file)
index 0000000..9a90a92
--- /dev/null
@@ -0,0 +1,358 @@
+MediaTek MT6358 Regulator
+
+All voltage regulators provided by the MT6358 PMIC are described as the
+subnodes of the MT6358 regulators node. Each regulator is named according
+to its regulator type, buck_<name> and ldo_<name>. The definition for each
+of these nodes is defined using the standard binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+The valid names for regulators are::
+BUCK:
+  buck_vdram1, buck_vcore, buck_vpa, buck_vproc11, buck_vproc12, buck_vgpu,
+  buck_vs2, buck_vmodem, buck_vs1
+LDO:
+  ldo_vdram2, ldo_vsim1, ldo_vibr, ldo_vrf12, ldo_vio18, ldo_vusb, ldo_vcamio,
+  ldo_vcamd, ldo_vcn18, ldo_vfe28, ldo_vsram_proc11, ldo_vcn28, ldo_vsram_others,
+  ldo_vsram_gpu, ldo_vxo22, ldo_vefuse, ldo_vaux18, ldo_vmch, ldo_vbif28,
+  ldo_vsram_proc12, ldo_vcama1, ldo_vemc, ldo_vio28, ldo_va12, ldo_vrf18,
+  ldo_vcn33_bt, ldo_vcn33_wifi, ldo_vcama2, ldo_vmc, ldo_vldo28, ldo_vaud28,
+  ldo_vsim2
+
+Example:
+
+       pmic {
+               compatible = "mediatek,mt6358";
+
+               mt6358regulator: mt6358regulator {
+                       compatible = "mediatek,mt6358-regulator";
+
+                       mt6358_vdram1_reg: buck_vdram1 {
+                               regulator-compatible = "buck_vdram1";
+                               regulator-name = "vdram1";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2087500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcore_reg: buck_vcore {
+                               regulator-name = "vcore";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vpa_reg: buck_vpa {
+                               regulator-name = "vpa";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <3650000>;
+                               regulator-ramp-delay = <50000>;
+                               regulator-enable-ramp-delay = <250>;
+                       };
+
+                       mt6358_vproc11_reg: buck_vproc11 {
+                               regulator-name = "vproc11";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vproc12_reg: buck_vproc12 {
+                               regulator-name = "vproc12";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vgpu_reg: buck_vgpu {
+                               regulator-name = "vgpu";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <200>;
+                       };
+
+                       mt6358_vs2_reg: buck_vs2 {
+                               regulator-name = "vs2";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <2087500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vmodem_reg: buck_vmodem {
+                               regulator-name = "vmodem";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <900>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vs1_reg: buck_vs1 {
+                               regulator-name = "vs1";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <2587500>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-enable-ramp-delay = <0>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vdram2_reg: ldo_vdram2 {
+                               regulator-name = "vdram2";
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <3300>;
+                       };
+
+                       mt6358_vsim1_reg: ldo_vsim1 {
+                               regulator-name = "vsim1";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+
+                       mt6358_vibr_reg: ldo_vibr {
+                               regulator-name = "vibr";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vrf12_reg: ldo_vrf12 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vrf12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       mt6358_vio18_reg: ldo_vio18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vio18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <2700>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vusb_reg: ldo_vusb {
+                               regulator-name = "vusb";
+                               regulator-min-microvolt = <3000000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcamio_reg: ldo_vcamio {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcamio";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcamd_reg: ldo_vcamd {
+                               regulator-name = "vcamd";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcn18_reg: ldo_vcn18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcn18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vfe28_reg: ldo_vfe28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vfe28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_proc11_reg: ldo_vsram_proc11 {
+                               regulator-name = "vsram_proc11";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcn28_reg: ldo_vcn28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vcn28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_others_reg: ldo_vsram_others {
+                               regulator-name = "vsram_others";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vsram_gpu_reg: ldo_vsram_gpu {
+                               regulator-name = "vsram_gpu";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                       };
+
+                       mt6358_vxo22_reg: ldo_vxo22 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vxo22";
+                               regulator-min-microvolt = <2200000>;
+                               regulator-max-microvolt = <2200000>;
+                               regulator-enable-ramp-delay = <120>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vefuse_reg: ldo_vefuse {
+                               regulator-name = "vefuse";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <1900000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vaux18_reg: ldo_vaux18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vaux18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vmch_reg: ldo_vmch {
+                               regulator-name = "vmch";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vbif28_reg: ldo_vbif28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vbif28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsram_proc12_reg: ldo_vsram_proc12 {
+                               regulator-name = "vsram_proc12";
+                               regulator-min-microvolt = <500000>;
+                               regulator-max-microvolt = <1293750>;
+                               regulator-ramp-delay = <6250>;
+                               regulator-enable-ramp-delay = <240>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vcama1_reg: ldo_vcama1 {
+                               regulator-name = "vcama1";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vemc_reg: ldo_vemc {
+                               regulator-name = "vemc";
+                               regulator-min-microvolt = <2900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vio28_reg: ldo_vio28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vio28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_va12_reg: ldo_va12 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "va12";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
+                               regulator-enable-ramp-delay = <270>;
+                               regulator-always-on;
+                       };
+
+                       mt6358_vrf18_reg: ldo_vrf18 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vrf18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-enable-ramp-delay = <120>;
+                       };
+
+                       mt6358_vcn33_bt_reg: ldo_vcn33_bt {
+                               regulator-name = "vcn33_bt";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3500000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcn33_wifi_reg: ldo_vcn33_wifi {
+                               regulator-name = "vcn33_wifi";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3500000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vcama2_reg: ldo_vcama2 {
+                               regulator-name = "vcama2";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vmc_reg: ldo_vmc {
+                               regulator-name = "vmc";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-enable-ramp-delay = <60>;
+                       };
+
+                       mt6358_vldo28_reg: ldo_vldo28 {
+                               regulator-name = "vldo28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vaud28_reg: ldo_vaud28 {
+                               compatible = "regulator-fixed";
+                               regulator-name = "vaud28";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-enable-ramp-delay = <270>;
+                       };
+
+                       mt6358_vsim2_reg: ldo_vsim2 {
+                               regulator-name = "vsim2";
+                               regulator-min-microvolt = <1700000>;
+                               regulator-max-microvolt = <3100000>;
+                               regulator-enable-ramp-delay = <540>;
+                       };
+               };
+       };
index 14d2eee..bab9f71 100644 (file)
@@ -22,9 +22,12 @@ RPMh resource.
 
 The names used for regulator nodes must match those supported by a given PMIC.
 Supported regulator node names:
+       PM8005:         smps1 - smps4
+       PM8009:         smps1 - smps2, ldo1 - ldo7
+       PM8150:         smps1 - smps10, ldo1 - ldo18
+       PM8150L:        smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
        PM8998:         smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
        PMI8998:        bob
-       PM8005:         smps1 - smps4
 
 ========================
 First Level Nodes - PMIC
@@ -33,9 +36,13 @@ First Level Nodes - PMIC
 - compatible
        Usage:      required
        Value type: <string>
-       Definition: Must be one of: "qcom,pm8998-rpmh-regulators",
-                   "qcom,pmi8998-rpmh-regulators" or
-                   "qcom,pm8005-rpmh-regulators".
+       Definition: Must be one of below:
+                   "qcom,pm8005-rpmh-regulators"
+                   "qcom,pm8009-rpmh-regulators"
+                   "qcom,pm8150-rpmh-regulators"
+                   "qcom,pm8150l-rpmh-regulators"
+                   "qcom,pm8998-rpmh-regulators"
+                   "qcom,pmi8998-rpmh-regulators"
 
 - qcom,pmic-id
        Usage:      required
diff --git a/Documentation/devicetree/bindings/regulator/sy8824x.txt b/Documentation/devicetree/bindings/regulator/sy8824x.txt
new file mode 100644 (file)
index 0000000..c5e9585
--- /dev/null
@@ -0,0 +1,24 @@
+SY8824C/SY8824E/SY20276 Voltage regulator
+
+Required properties:
+- compatible: Must be one of the following.
+       "silergy,sy8824c"
+       "silergy,sy8824e"
+       "silergy,sy20276"
+       "silergy,sy20278"
+- reg: I2C slave address
+
+Any property defined as part of the core regulator binding, defined in
+./regulator.txt, can also be used.
+
+Example:
+
+       vcore: regulator@00 {
+               compatible = "silergy,sy8824c";
+               reg = <0x66>;
+               regulator-name = "vcore";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <1150000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
index 74a91c4..549f804 100644 (file)
@@ -71,3 +71,10 @@ Example:
                regulator-min-microvolt  = <1000000>;
                regulator-max-microvolt  = <3000000>;
        };
+
+For twl6030 regulators/LDOs:
+
+ - ti,retain-on-reset: Does not turn off the supplies during warm
+                       reset. Could be needed for VMMC, as TWL6030
+                       reset sequence for this signal does not comply
+                       with the SD specification.
index c9919f4..94fd38b 100644 (file)
@@ -13,6 +13,7 @@ this layer. These clocks and resets should be described in each property.
 Required properties:
 - compatible: Should be
     "socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC
+    "socionext,uniphier-pro5-usb3-regulator" - for Pro5 SoC
     "socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC
     "socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC
     "socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC
@@ -20,12 +21,12 @@ Required properties:
 - clocks: A list of phandles to the clock gate for USB3 glue layer.
        According to the clock-names, appropriate clocks are required.
 - clock-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 - resets: A list of phandles to the reset control for USB3 glue layer.
        According to the reset-names, appropriate resets are required.
 - reset-names: Should contain
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoCs
     "link"        - for others
 
 See Documentation/devicetree/bindings/regulator/regulator.txt
diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt
new file mode 100644 (file)
index 0000000..a388005
--- /dev/null
@@ -0,0 +1,47 @@
+* Nuvoton FLASH Interface Unit (FIU) SPI Controller
+
+NPCM FIU supports single, dual and quad communication interface.
+
+The NPCM7XX supports three FIU modules,
+FIU0 and FIUx supports two chip selects,
+FIU3 support four chip select.
+
+Required properties:
+  - compatible : "nuvoton,npcm750-fiu" for the NPCM7XX BMC
+  - #address-cells : should be 1.
+  - #size-cells : should be 0.
+  - reg : the first contains the register location and length,
+          the second contains the memory mapping address and length
+  - reg-names: Should contain the reg names "control" and "memory"
+  - clocks : phandle of FIU reference clock.
+
+Required properties in case the pins can be muxed:
+  - pinctrl-names : a pinctrl state named "default" must be defined.
+  - pinctrl-0 : phandle referencing pin configuration of the device.
+
+Optional property:
+  - nuvoton,spix-mode: enable spix-mode for an expansion bus to an ASIC or CPLD.
+
+Aliases:
+- All the FIU controller nodes should be represented in the aliases node using
+  the following format 'fiu{n}' where n is a unique number for the alias.
+  In the NPCM7XX BMC:
+               fiu0 represent fiu 0 controller
+               fiu1 represent fiu 3 controller
+               fiu2 represent fiu x controller
+
+Example:
+fiu3: spi@c00000000 {
+       compatible = "nuvoton,npcm750-fiu";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0xfb000000 0x1000>, <0x80000000 0x10000000>;
+       reg-names = "control", "memory";
+       clocks = <&clk NPCM7XX_CLK_AHB>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi3_pins>;
+       spi-nor@0 {
+                       ...
+       };
+};
+
index a02e2fe..7323392 100644 (file)
@@ -31,7 +31,7 @@ properties:
       If that property is used, the number of chip selects will be
       increased automatically with max(cs-gpios, hardware chip selects).
 
-      So if, for example, the controller has 2 CS lines, and the
+      So if, for example, the controller has 4 CS lines, and the
       cs-gpios looks like this
         cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>;
 
index e8f1d62..69dc5d5 100644 (file)
@@ -3,9 +3,8 @@
 Required properties:
   - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi",
                 "fsl,imx7d-qspi", "fsl,imx6ul-qspi",
-                "fsl,ls1021a-qspi"
+                "fsl,ls1021a-qspi", "fsl,ls2080a-qspi"
                 or
-                "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi",
                 "fsl,ls1043a-qspi" followed by "fsl,ls1021a-qspi"
   - reg : the first contains the register location and length,
           the second contains the memory mapping address and length
@@ -34,7 +33,11 @@ qspi0: quadspi@40044000 {
        clock-names = "qspi_en", "qspi";
 
        flash0: s25fl128s@0 {
-               ....
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,s25fl128s", "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+               reg = <0>;
        };
 };
 
index c0f6c8e..3a8079e 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
     - mediatek,mt2701-spi: for mt2701 platforms
     - mediatek,mt2712-spi: for mt2712 platforms
     - mediatek,mt6589-spi: for mt6589 platforms
+    - mediatek,mt6765-spi: for mt6765 platforms
     - mediatek,mt7622-spi: for mt7622 platforms
     - "mediatek,mt7629-spi", "mediatek,mt7622-spi": for mt7629 platforms
     - mediatek,mt8135-spi: for mt8135 platforms
index 8de589b..2567c82 100644 (file)
@@ -25,18 +25,23 @@ data by ADI software channels at the same time, or two parallel routine of setti
 ADI registers will make ADI controller registers chaos to lead incorrect results.
 Then we need one hardware spinlock to synchronize between the multiple subsystems.
 
+The new version ADI controller supplies multiple master channels for different
+subsystem accessing, that means no need to add hardware spinlock to synchronize,
+thus change the hardware spinlock support to be optional to keep backward
+compatibility.
+
 Required properties:
 - compatible: Should be "sprd,sc9860-adi".
 - reg: Offset and length of ADI-SPI controller register space.
-- hwlocks: Reference to a phandle of a hwlock provider node.
-- hwlock-names: Reference to hwlock name strings defined in the same order
-       as the hwlocks, should be "adi".
 - #address-cells: Number of cells required to define a chip select address
        on the ADI-SPI bus. Should be set to 1.
 - #size-cells: Size of cells required to define a chip select address size
        on the ADI-SPI bus. Should be set to 0.
 
 Optional properties:
+- hwlocks: Reference to a phandle of a hwlock provider node.
+- hwlock-names: Reference to hwlock name strings defined in the same order
+       as the hwlocks, should be "adi".
 - sprd,hw-channels: This is an array of channel values up to 49 channels.
        The first value specifies the hardware channel id which is used to
        transfer data triggered by hardware automatically, and the second
index 2e742d3..870ac52 100644 (file)
@@ -104,6 +104,8 @@ properties:
           - infineon,slb9645tt
             # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
           - infineon,tlv493d-a1b6
+            # Inspur Power System power supply unit version 1
+          - inspur,ipsps1
             # Intersil ISL29028 Ambient Light and Proximity Sensor
           - isil,isl29028
             # Intersil ISL29030 Ambient Light and Proximity Sensor
index 6992bbb..d61a203 100644 (file)
@@ -575,6 +575,8 @@ patternProperties:
     description: Micro Crystal AG
   "^micron,.*":
     description: Micron Technology Inc.
+  "^microsoft,.*":
+    description: Microsoft Corporation
   "^mikroe,.*":
     description: MikroElektronika d.o.o.
   "^miniand,.*":
index 921c71a..3fdb324 100644 (file)
@@ -69,9 +69,9 @@ driver code:
 
 The code implementing a gpio_chip should support multiple instances of the
 controller, preferably using the driver model. That code will configure each
-gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
-Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
-when it is unavoidable.
+gpio_chip and issue gpiochip_add(), gpiochip_add_data(), or
+devm_gpiochip_add_data().  Removing a GPIO controller should be rare; use
+gpiochip_remove() when it is unavoidable.
 
 Often a gpio_chip is part of an instance-specific structure with states not
 exposed by the GPIO interfaces, such as addressing, power management, and more.
@@ -259,7 +259,7 @@ most often cascaded off a parent interrupt controller, and in some special
 cases the GPIO logic is melded with a SoC's primary interrupt controller.
 
 The IRQ portions of the GPIO block are implemented using an irq_chip, using
-the header <linux/irq.h>. So basically such a driver is utilizing two sub-
+the header <linux/irq.h>. So this combined driver is utilizing two sub-
 systems simultaneously: gpio and irq.
 
 It is legal for any IRQ consumer to request an IRQ from any irqchip even if it
@@ -391,25 +391,119 @@ Infrastructure helpers for GPIO irqchips
 ----------------------------------------
 
 To help out in handling the set-up and management of GPIO irqchips and the
-associated irqdomain and resource allocation callbacks, the gpiolib has
-some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
-symbol:
-
-- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It
-  will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
-  callbacks need to embed the gpio_chip in its state container and obtain a
-  pointer to the container using container_of().
-  (See Documentation/driver-api/driver-model/design-patterns.rst)
+associated irqdomain and resource allocation callbacks. These are activated
+by selecting the Kconfig symbol GPIOLIB_IRQCHIP. If the symbol
+IRQ_DOMAIN_HIERARCHY is also selected, hierarchical helpers will also be
+provided. A big portion of overhead code will be managed by gpiolib,
+under the assumption that your interrupts are 1-to-1-mapped to the
+GPIO line index:
+
+  GPIO line offset   Hardware IRQ
+  0                  0
+  1                  1
+  2                  2
+  ...                ...
+  ngpio-1            ngpio-1
+
+If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask
+and the flag need_valid_mask in gpio_irq_chip can be used to mask off some
+lines as invalid for associating with IRQs.
+
+The preferred way to set up the helpers is to fill in the
+struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
+If you do this, the additional irq_chip will be set up by gpiolib at the
+same time as setting up the rest of the GPIO functionality. The following
+is a typical example of a cascaded interrupt handler using gpio_irq_chip:
+
+  /* Typical state container with dynamic irqchip */
+  struct my_gpio {
+      struct gpio_chip gc;
+      struct irq_chip irq;
+  };
+
+  int irq; /* from platform etc */
+  struct my_gpio *g;
+  struct gpio_irq_chip *girq;
+
+  /* Set up the irqchip dynamically */
+  g->irq.name = "my_gpio_irq";
+  g->irq.irq_ack = my_gpio_ack_irq;
+  g->irq.irq_mask = my_gpio_mask_irq;
+  g->irq.irq_unmask = my_gpio_unmask_irq;
+  g->irq.irq_set_type = my_gpio_set_irq_type;
+
+  /* Get a pointer to the gpio_irq_chip */
+  girq = &g->gc.irq;
+  girq->chip = &g->irq;
+  girq->parent_handler = ftgpio_gpio_irq_handler;
+  girq->num_parents = 1;
+  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+                               GFP_KERNEL);
+  if (!girq->parents)
+      return -ENOMEM;
+  girq->default_type = IRQ_TYPE_NONE;
+  girq->handler = handle_bad_irq;
+  girq->parents[0] = irq;
+
+  return devm_gpiochip_add_data(dev, &g->gc, g);
+
+The helper support using hierarchical interrupt controllers as well.
+In this case the typical set-up will look like this:
+
+  /* Typical state container with dynamic irqchip */
+  struct my_gpio {
+      struct gpio_chip gc;
+      struct irq_chip irq;
+      struct fwnode_handle *fwnode;
+  };
+
+  int irq; /* from platform etc */
+  struct my_gpio *g;
+  struct gpio_irq_chip *girq;
+
+  /* Set up the irqchip dynamically */
+  g->irq.name = "my_gpio_irq";
+  g->irq.irq_ack = my_gpio_ack_irq;
+  g->irq.irq_mask = my_gpio_mask_irq;
+  g->irq.irq_unmask = my_gpio_unmask_irq;
+  g->irq.irq_set_type = my_gpio_set_irq_type;
+
+  /* Get a pointer to the gpio_irq_chip */
+  girq = &g->gc.irq;
+  girq->chip = &g->irq;
+  girq->default_type = IRQ_TYPE_NONE;
+  girq->handler = handle_bad_irq;
+  girq->fwnode = g->fwnode;
+  girq->parent_domain = parent;
+  girq->child_to_parent_hwirq = my_gpio_child_to_parent_hwirq;
+
+  return devm_gpiochip_add_data(dev, &g->gc, g);
+
+As you can see pretty similar, but you do not supply a parent handler for
+the IRQ, instead a parent irqdomain, an fwnode for the hardware and
+a funcion .child_to_parent_hwirq() that has the purpose of looking up
+the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
+As always it is good to look at examples in the kernel tree for advice
+on how to find the required pieces.
+
+The old way of adding irqchips to gpiochips after registration is also still
+available but we try to move away from this:
+
+- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
+  gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ
+  callbacks, so the callbacks need to embed the gpio_chip in its state
+  container and obtain a pointer to the container using container_of().
+  (See Documentation/driver-model/design-patterns.txt)
 
 - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
   as discussed above regarding different types of cascaded irqchips. The
   cascaded irq has to be handled by a threaded interrupt handler.
   Apart from that it works exactly like the chained irqchip.
 
-- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a
-  gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
-  data. Notice that we pass is as the handler data, since the irqchip data is
-  likely used by the parent irqchip.
+- DEPRECATED: gpiochip_set_chained_irqchip(): sets up a chained cascaded irq
+  handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip*
+  as handler data. Notice that we pass is as the handler data, since the
+  irqchip data is likely used by the parent irqchip.
 
 - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
   gpio_chip from a parent IRQ. As the parent IRQ has usually been
@@ -418,11 +512,11 @@ symbol:
 
 If there is a need to exclude certain GPIO lines from the IRQ domain handled by
 these helpers, we can set .irq.need_valid_mask of the gpiochip before
-``[devm_]gpiochip_add_data()`` is called. This allocates an .irq.valid_mask with as
-many bits set as there are GPIO lines in the chip, each bit representing line
-0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask
-must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested()
-is called.
+devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an
+.irq.valid_mask with as many bits set as there are GPIO lines in the chip, each
+bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits
+from this mask. The mask must be filled in before gpiochip_irqchip_add() or
+gpiochip_irqchip_add_nested() is called.
 
 To use the helpers please keep the following in mind:
 
diff --git a/Documentation/driver-api/sgi-ioc4.rst b/Documentation/driver-api/sgi-ioc4.rst
deleted file mode 100644 (file)
index 7270922..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-====================================
-SGI IOC4 PCI (multi function) device
-====================================
-
-The SGI IOC4 PCI device is a bit of a strange beast, so some notes on
-it are in order.
-
-First, even though the IOC4 performs multiple functions, such as an
-IDE controller, a serial controller, a PS/2 keyboard/mouse controller,
-and an external interrupt mechanism, it's not implemented as a
-multifunction device.  The consequence of this from a software
-standpoint is that all these functions share a single IRQ, and
-they can't all register to own the same PCI device ID.  To make
-matters a bit worse, some of the register blocks (and even registers
-themselves) present in IOC4 are mixed-purpose between these several
-functions, meaning that there's no clear "owning" device driver.
-
-The solution is to organize the IOC4 driver into several independent
-drivers, "ioc4", "sgiioc4", and "ioc4_serial".  Note that there is no
-PS/2 controller driver as this functionality has never been wired up
-on a shipping IO card.
-
-ioc4
-====
-This is the core (or shim) driver for IOC4.  It is responsible for
-initializing the basic functionality of the chip, and allocating
-the PCI resources that are shared between the IOC4 functions.
-
-This driver also provides registration functions that the other
-IOC4 drivers can call to make their presence known.  Each driver
-needs to provide a probe and remove function, which are invoked
-by the core driver at appropriate times.  The interface of these
-IOC4 function probe and remove operations isn't precisely the same
-as PCI device probe and remove operations, but is logically the
-same operation.
-
-sgiioc4
-=======
-This is the IDE driver for IOC4.  Its name isn't very descriptive
-simply for historical reasons (it used to be the only IOC4 driver
-component).  There's not much to say about it other than it hooks
-up to the ioc4 driver via the appropriate registration, probe, and
-remove functions.
-
-ioc4_serial
-===========
-This is the serial driver for IOC4.  There's not much to say about it
-other than it hooks up to the ioc4 driver via the appropriate registration,
-probe, and remove functions.
index 7fc2e24..cae7be2 100644 (file)
@@ -21,7 +21,7 @@
     |       nds32: | TODO |
     |       nios2: | TODO |
     |    openrisc: | TODO |
-    |      parisc: | TODO |
+    |      parisc: |  ok  |
     |     powerpc: |  ok  |
     |       riscv: | TODO |
     |        s390: |  ok  |
index 68f2669..4fae046 100644 (file)
@@ -21,7 +21,7 @@
     |       nds32: | TODO |
     |       nios2: | TODO |
     |    openrisc: | TODO |
-    |      parisc: | TODO |
+    |      parisc: |  ok  |
     |     powerpc: |  ok  |
     |       riscv: | TODO |
     |        s390: | TODO |
diff --git a/Documentation/hwmon/ads1015.rst b/Documentation/hwmon/ads1015.rst
deleted file mode 100644 (file)
index e0951c4..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Kernel driver ads1015
-=====================
-
-Supported chips:
-
-  * Texas Instruments ADS1015
-
-    Prefix: 'ads1015'
-
-    Datasheet: Publicly available at the Texas Instruments website:
-
-              http://focus.ti.com/lit/ds/symlink/ads1015.pdf
-
-  * Texas Instruments ADS1115
-
-    Prefix: 'ads1115'
-
-    Datasheet: Publicly available at the Texas Instruments website:
-
-              http://focus.ti.com/lit/ds/symlink/ads1115.pdf
-
-Authors:
-       Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
-
-Description
------------
-
-This driver implements support for the Texas Instruments ADS1015/ADS1115.
-
-This device is a 12/16-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-The inputs can be made available by 8 sysfs input files in0_input - in7_input:
-
-  - in0: Voltage over AIN0 and AIN1.
-  - in1: Voltage over AIN0 and AIN3.
-  - in2: Voltage over AIN1 and AIN3.
-  - in3: Voltage over AIN2 and AIN3.
-  - in4: Voltage over AIN0 and GND.
-  - in5: Voltage over AIN1 and GND.
-  - in6: Voltage over AIN2 and GND.
-  - in7: Voltage over AIN3 and GND.
-
-Which inputs are available can be configured using platform data or devicetree.
-
-By default all inputs are exported.
-
-Platform Data
--------------
-
-In linux/platform_data/ads1015.h platform data is defined, channel_data contains
-configuration data for the used input combinations:
-
-- pga is the programmable gain amplifier (values are full scale)
-
-    - 0: +/- 6.144 V
-    - 1: +/- 4.096 V
-    - 2: +/- 2.048 V
-    - 3: +/- 1.024 V
-    - 4: +/- 0.512 V
-    - 5: +/- 0.256 V
-
-- data_rate in samples per second
-
-    - 0: 128
-    - 1: 250
-    - 2: 490
-    - 3: 920
-    - 4: 1600
-    - 5: 2400
-    - 6: 3300
-
-Example::
-
-  struct ads1015_platform_data data = {
-       .channel_data = {
-               [2] = { .enabled = true, .pga = 1, .data_rate = 0 },
-               [4] = { .enabled = true, .pga = 4, .data_rate = 5 },
-       }
-  };
-
-In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
-(FS +/- 0.512 V, 2400 SPS) would be created.
-
-Devicetree
-----------
-
-Configuration is also possible via devicetree:
-Documentation/devicetree/bindings/hwmon/ads1015.txt
index ee090e5..8147c3f 100644 (file)
@@ -30,7 +30,6 @@ Hardware Monitoring Kernel Drivers
    adm1031
    adm1275
    adm9240
-   ads1015
    ads7828
    adt7410
    adt7411
@@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers
    pcf8591
    pmbus
    powr1220
+   pxe1610
    pwm-fan
    raspberrypi-hwmon
    sch5627
diff --git a/Documentation/hwmon/inspur-ipsps1.rst b/Documentation/hwmon/inspur-ipsps1.rst
new file mode 100644 (file)
index 0000000..2b871ae
--- /dev/null
@@ -0,0 +1,79 @@
+Kernel driver inspur-ipsps1
+=======================
+
+Supported chips:
+
+  * Inspur Power System power supply unit
+
+Author: John Wang <wangzqbj@inspur.com>
+
+Description
+-----------
+
+This driver supports Inspur Power System power supplies. This driver
+is a client to the core PMBus driver.
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+Sysfs entries
+-------------
+
+The following attributes are supported:
+
+======================= ======================================================
+curr1_input            Measured input current
+curr1_label            "iin"
+curr1_max              Maximum current
+curr1_max_alarm                Current high alarm
+curr2_input            Measured output current in mA.
+curr2_label            "iout1"
+curr2_crit             Critical maximum current
+curr2_crit_alarm       Current critical high alarm
+curr2_max              Maximum current
+curr2_max_alarm                Current high alarm
+
+fan1_alarm             Fan 1 warning.
+fan1_fault             Fan 1 fault.
+fan1_input             Fan 1 speed in RPM.
+
+in1_alarm              Input voltage under-voltage alarm.
+in1_input              Measured input voltage in mV.
+in1_label              "vin"
+in2_input              Measured output voltage in mV.
+in2_label              "vout1"
+in2_lcrit              Critical minimum output voltage
+in2_lcrit_alarm                Output voltage critical low alarm
+in2_max                        Maximum output voltage
+in2_max_alarm          Output voltage high alarm
+in2_min                        Minimum output voltage
+in2_min_alarm          Output voltage low alarm
+
+power1_alarm           Input fault or alarm.
+power1_input           Measured input power in uW.
+power1_label           "pin"
+power1_max             Input power limit
+power2_max_alarm       Output power high alarm
+power2_max             Output power limit
+power2_input           Measured output power in uW.
+power2_label           "pout"
+
+temp[1-3]_input                Measured temperature
+temp[1-2]_max          Maximum temperature
+temp[1-3]_max_alarm    Temperature high alarm
+
+vendor                 Manufacturer name
+model                  Product model
+part_number            Product part number
+serial_number          Product serial number
+fw_version             Firmware version
+hw_version             Hardware version
+mode                   Work mode. Can be set to active or
+                       standby, when set to standby, PSU will
+                       automatically switch between standby
+                       and redundancy mode.
+======================= ======================================================
index ba8acbd..e749f82 100644 (file)
@@ -119,9 +119,9 @@ Supported chips:
 
               http://www.ti.com/product/tmp275
 
-  * NXP LM75B
+  * NXP LM75B, PCT2075
 
-    Prefix: 'lm75b'
+    Prefix: 'lm75b', 'pct2075'
 
     Addresses scanned: none
 
@@ -129,6 +129,8 @@ Supported chips:
 
               http://www.nxp.com/documents/data_sheet/LM75B.pdf
 
+               http://www.nxp.com/docs/en/data-sheet/PCT2075.pdf
+
 Author: Frodo Looijaard <frodol@dds.nl>
 
 Description
diff --git a/Documentation/hwmon/pxe1610 b/Documentation/hwmon/pxe1610
deleted file mode 100644 (file)
index 211cede..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Kernel driver pxe1610
-=====================
-
-Supported chips:
-  * Infineon PXE1610
-    Prefix: 'pxe1610'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-  * Infineon PXE1110
-    Prefix: 'pxe1110'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-  * Infineon PXM1310
-    Prefix: 'pxm1310'
-    Addresses scanned: -
-    Datasheet: Datasheet is not publicly available.
-
-Author: Vijay Khemka <vijaykhemka@fb.com>
-
-
-Description
------------
-
-PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
-and compliant to
-       -- Intel VR13 DC-DC converter specifications.
-       -- Intel SVID protocol.
-Used for Vcore power regulation for Intel VR13 based microprocessors
-       -- Servers, Workstations, and High-end desktops
-
-PXM1310 is a Multi-rail Controller and it is compliant to
-       -- Intel VR13 DC-DC converter specifications.
-       -- Intel SVID protocol.
-Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
-IMVP8 based systems
-
-
-Usage Notes
------------
-
-This driver does not probe for PMBus devices. You will have
-to instantiate devices explicitly.
-
-Example: the following commands will load the driver for an PXE1610
-at address 0x70 on I2C bus #4:
-
-# modprobe pxe1610
-# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
-
-It can also be instantiated by declaring in device tree
-
-
-Sysfs attributes
-----------------
-
-curr1_label            "iin"
-curr1_input            Measured input current
-curr1_alarm            Current high alarm
-
-curr[2-4]_label                "iout[1-3]"
-curr[2-4]_input                Measured output current
-curr[2-4]_crit         Critical maximum current
-curr[2-4]_crit_alarm   Current critical high alarm
-
-in1_label              "vin"
-in1_input              Measured input voltage
-in1_crit               Critical maximum input voltage
-in1_crit_alarm         Input voltage critical high alarm
-
-in[2-4]_label          "vout[1-3]"
-in[2-4]_input          Measured output voltage
-in[2-4]_lcrit          Critical minimum output voltage
-in[2-4]_lcrit_alarm    Output voltage critical low alarm
-in[2-4]_crit           Critical maximum output voltage
-in[2-4]_crit_alarm     Output voltage critical high alarm
-
-power1_label           "pin"
-power1_input           Measured input power
-power1_alarm           Input power high alarm
-
-power[2-4]_label       "pout[1-3]"
-power[2-4]_input       Measured output power
-
-temp[1-3]_input                Measured temperature
-temp[1-3]_crit         Critical high temperature
-temp[1-3]_crit_alarm   Chip temperature critical high alarm
-temp[1-3]_max          Maximum temperature
-temp[1-3]_max_alarm    Chip temperature high alarm
diff --git a/Documentation/hwmon/pxe1610.rst b/Documentation/hwmon/pxe1610.rst
new file mode 100644 (file)
index 0000000..4f23888
--- /dev/null
@@ -0,0 +1,107 @@
+Kernel driver pxe1610
+=====================
+
+Supported chips:
+
+  * Infineon PXE1610
+
+    Prefix: 'pxe1610'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXE1110
+
+    Prefix: 'pxe1110'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+  * Infineon PXM1310
+
+    Prefix: 'pxm1310'
+
+    Addresses scanned: -
+
+    Datasheet: Datasheet is not publicly available.
+
+Author: Vijay Khemka <vijaykhemka@fb.com>
+
+
+Description
+-----------
+
+PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
+and compliant to
+
+       - Intel VR13 DC-DC converter specifications.
+       - Intel SVID protocol.
+
+Used for Vcore power regulation for Intel VR13 based microprocessors
+
+       - Servers, Workstations, and High-end desktops
+
+PXM1310 is a Multi-rail Controller and it is compliant to
+
+       - Intel VR13 DC-DC converter specifications.
+       - Intel SVID protocol.
+
+Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
+IMVP8 based systems
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have
+to instantiate devices explicitly.
+
+Example: the following commands will load the driver for an PXE1610
+at address 0x70 on I2C bus #4::
+
+    # modprobe pxe1610
+    # echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
+
+It can also be instantiated by declaring in device tree
+
+
+Sysfs attributes
+----------------
+
+======================  ====================================
+curr1_label            "iin"
+curr1_input            Measured input current
+curr1_alarm            Current high alarm
+
+curr[2-4]_label                "iout[1-3]"
+curr[2-4]_input                Measured output current
+curr[2-4]_crit         Critical maximum current
+curr[2-4]_crit_alarm   Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in[2-4]_label          "vout[1-3]"
+in[2-4]_input          Measured output voltage
+in[2-4]_lcrit          Critical minimum output voltage
+in[2-4]_lcrit_alarm    Output voltage critical low alarm
+in[2-4]_crit           Critical maximum output voltage
+in[2-4]_crit_alarm     Output voltage critical high alarm
+
+power1_label           "pin"
+power1_input           Measured input power
+power1_alarm           Input power high alarm
+
+power[2-4]_label       "pout[1-3]"
+power[2-4]_input       Measured output power
+
+temp[1-3]_input                Measured temperature
+temp[1-3]_crit         Critical high temperature
+temp[1-3]_crit_alarm   Chip temperature critical high alarm
+temp[1-3]_max          Maximum temperature
+temp[1-3]_max_alarm    Chip temperature high alarm
+======================  ====================================
index aa11633..9b0f1ee 100644 (file)
@@ -19,7 +19,17 @@ Supported chips:
 
     Addresses scanned: none
 
-    Datasheet: Not publicly available
+    Datasheet: http://www.sensirion.com/file/datasheet_shtw1
+
+
+
+  * Sensirion SHTC3
+
+    Prefix: 'shtc3'
+
+    Addresses scanned: none
+
+    Datasheet: http://www.sensirion.com/file/datasheet_shtc3
 
 
 
@@ -30,10 +40,9 @@ Author:
 Description
 -----------
 
-This driver implements support for the Sensirion SHTC1 chip, a humidity and
-temperature sensor. Temperature is measured in degrees celsius, relative
-humidity is expressed as a percentage. Driver can be used as well for SHTW1
-chip, which has the same electrical interface.
+This driver implements support for the Sensirion SHTC1, SHTW1, and SHTC3
+chips, a humidity and temperature sensor. Temperature is measured in degrees
+celsius, relative humidity is expressed as a percentage.
 
 The device communicates with the I2C protocol. All sensors are set to I2C
 address 0x70. See Documentation/i2c/instantiating-devices for methods to
index 452fc28..9a218ea 100644 (file)
@@ -20,6 +20,10 @@ increase the chances of your change being accepted.
   errors, no warnings, and few if any check messages. If there are any
   messages, please be prepared to explain.
 
+* Please use the standard multi-line comment style. Do not mix C and C++
+  style comments in a single driver (with the exception of the SPDX license
+  identifier).
+
 * If your patch generates checkpatch errors, warnings, or check messages,
   please refrain from explanations such as "I prefer that coding style".
   Keep in mind that each unnecessary message helps hiding a real problem,
@@ -120,8 +124,8 @@ increase the chances of your change being accepted.
   completely initialize your chip and your driver first, then register with
   the hwmon subsystem.
 
-* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove
-  function, hwmon_device_register_with_groups() to register your driver with the
+* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
+  function, hwmon_device_register_with_info() to register your driver with the
   hwmon subsystem. Try using devm_add_action() instead of a remove function if
   possible. Do not use hwmon_device_register().
 
index b70b70d..0dd3f74 100644 (file)
@@ -506,21 +506,3 @@ Drivers should ignore the changes to TLS the device feature flags.
 These flags will be acted upon accordingly by the core ``ktls`` code.
 TLS device feature flags only control adding of new TLS connection
 offloads, old connections will remain active after flags are cleared.
-
-Known bugs
-==========
-
-skb_orphan() leaks clear text
------------------------------
-
-Currently drivers depend on the :c:member:`sk` member of
-:c:type:`struct sk_buff <sk_buff>` to identify segments requiring
-encryption. Any operation which removes or does not preserve the socket
-association such as :c:func:`skb_orphan` or :c:func:`skb_clone`
-will cause the driver to miss the packets and lead to clear text leaks.
-
-Redirects leak clear text
--------------------------
-
-In the RX direction, if segment has already been decrypted by the device
-and it gets redirected or mirrored - clear text will be transmitted out.
index 949d5dc..0104830 100644 (file)
@@ -204,8 +204,8 @@ Ethernet device, which instead of receiving packets from a physical
 media, receives them from user space program and instead of sending 
 packets via physical media sends them to the user space program. 
 
-Let's say that you configured IPX on the tap0, then whenever 
-the kernel sends an IPX packet to tap0, it is passed to the application
+Let's say that you configured IPv6 on the tap0, then whenever
+the kernel sends an IPv6 packet to tap0, it is passed to the application
 (VTun for example). The application encrypts, compresses and sends it to 
 the other side over TCP or UDP. The application on the other side decompresses
 and decrypts the data received and writes the packet to the TAP device, 
diff --git a/Documentation/process/embargoed-hardware-issues.rst b/Documentation/process/embargoed-hardware-issues.rst
new file mode 100644 (file)
index 0000000..4026363
--- /dev/null
@@ -0,0 +1,279 @@
+Embargoed hardware issues
+=========================
+
+Scope
+-----
+
+Hardware issues which result in security problems are a different category
+of security bugs than pure software bugs which only affect the Linux
+kernel.
+
+Hardware issues like Meltdown, Spectre, L1TF etc. must be treated
+differently because they usually affect all Operating Systems ("OS") and
+therefore need coordination across different OS vendors, distributions,
+hardware vendors and other parties. For some of the issues, software
+mitigations can depend on microcode or firmware updates, which need further
+coordination.
+
+.. _Contact:
+
+Contact
+-------
+
+The Linux kernel hardware security team is separate from the regular Linux
+kernel security team.
+
+The team only handles the coordination of embargoed hardware security
+issues.  Reports of pure software security bugs in the Linux kernel are not
+handled by this team and the reporter will be guided to contact the regular
+Linux kernel security team (:ref:`Documentation/admin-guide/
+<securitybugs>`) instead.
+
+The team can be contacted by email at <hardware-security@kernel.org>. This
+is a private list of security officers who will help you to coordinate an
+issue according to our documented process.
+
+The list is encrypted and email to the list can be sent by either PGP or
+S/MIME encrypted and must be signed with the reporter's PGP key or S/MIME
+certificate. The list's PGP key and S/MIME certificate are available from
+https://www.kernel.org/....
+
+While hardware security issues are often handled by the affected hardware
+vendor, we welcome contact from researchers or individuals who have
+identified a potential hardware flaw.
+
+Hardware security officers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The current team of hardware security officers:
+
+  - Linus Torvalds (Linux Foundation Fellow)
+  - Greg Kroah-Hartman (Linux Foundation Fellow)
+  - Thomas Gleixner (Linux Foundation Fellow)
+
+Operation of mailing-lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The encrypted mailing-lists which are used in our process are hosted on
+Linux Foundation's IT infrastructure. By providing this service Linux
+Foundation's director of IT Infrastructure security technically has the
+ability to access the embargoed information, but is obliged to
+confidentiality by his employment contract. Linux Foundation's director of
+IT Infrastructure security is also responsible for the kernel.org
+infrastructure.
+
+The Linux Foundation's current director of IT Infrastructure security is
+Konstantin Ryabitsev.
+
+
+Non-disclosure agreements
+-------------------------
+
+The Linux kernel hardware security team is not a formal body and therefore
+unable to enter into any non-disclosure agreements.  The kernel community
+is aware of the sensitive nature of such issues and offers a Memorandum of
+Understanding instead.
+
+
+Memorandum of Understanding
+---------------------------
+
+The Linux kernel community has a deep understanding of the requirement to
+keep hardware security issues under embargo for coordination between
+different OS vendors, distributors, hardware vendors and other parties.
+
+The Linux kernel community has successfully handled hardware security
+issues in the past and has the necessary mechanisms in place to allow
+community compliant development under embargo restrictions.
+
+The Linux kernel community has a dedicated hardware security team for
+initial contact, which oversees the process of handling such issues under
+embargo rules.
+
+The hardware security team identifies the developers (domain experts) who
+will form the initial response team for a particular issue. The initial
+response team can bring in further developers (domain experts) to address
+the issue in the best technical way.
+
+All involved developers pledge to adhere to the embargo rules and to keep
+the received information confidential. Violation of the pledge will lead to
+immediate exclusion from the current issue and removal from all related
+mailing-lists. In addition, the hardware security team will also exclude
+the offender from future issues. The impact of this consequence is a highly
+effective deterrent in our community. In case a violation happens the
+hardware security team will inform the involved parties immediately. If you
+or anyone becomes aware of a potential violation, please report it
+immediately to the Hardware security officers.
+
+
+Process
+^^^^^^^
+
+Due to the globally distributed nature of Linux kernel development,
+face-to-face meetings are almost impossible to address hardware security
+issues.  Phone conferences are hard to coordinate due to time zones and
+other factors and should be only used when absolutely necessary. Encrypted
+email has been proven to be the most effective and secure communication
+method for these types of issues.
+
+Start of Disclosure
+"""""""""""""""""""
+
+Disclosure starts by contacting the Linux kernel hardware security team by
+email. This initial contact should contain a description of the problem and
+a list of any known affected hardware. If your organization builds or
+distributes the affected hardware, we encourage you to also consider what
+other hardware could be affected.
+
+The hardware security team will provide an incident-specific encrypted
+mailing-list which will be used for initial discussion with the reporter,
+further disclosure and coordination.
+
+The hardware security team will provide the disclosing party a list of
+developers (domain experts) who should be informed initially about the
+issue after confirming with the developers  that they will adhere to this
+Memorandum of Understanding and the documented process. These developers
+form the initial response team and will be responsible for handling the
+issue after initial contact. The hardware security team is supporting the
+response team, but is not necessarily involved in the mitigation
+development process.
+
+While individual developers might be covered by a non-disclosure agreement
+via their employer, they cannot enter individual non-disclosure agreements
+in their role as Linux kernel developers. They will, however, agree to
+adhere to this documented process and the Memorandum of Understanding.
+
+
+Disclosure
+""""""""""
+
+The disclosing party provides detailed information to the initial response
+team via the specific encrypted mailing-list.
+
+From our experience the technical documentation of these issues is usually
+a sufficient starting point and further technical clarification is best
+done via email.
+
+Mitigation development
+""""""""""""""""""""""
+
+The initial response team sets up an encrypted mailing-list or repurposes
+an existing one if appropriate. The disclosing party should provide a list
+of contacts for all other parties who have already been, or should be,
+informed about the issue. The response team contacts these parties so they
+can name experts who should be subscribed to the mailing-list.
+
+Using a mailing-list is close to the normal Linux development process and
+has been successfully used in developing mitigations for various hardware
+security issues in the past.
+
+The mailing-list operates in the same way as normal Linux development.
+Patches are posted, discussed and reviewed and if agreed on applied to a
+non-public git repository which is only accessible to the participating
+developers via a secure connection. The repository contains the main
+development branch against the mainline kernel and backport branches for
+stable kernel versions as necessary.
+
+The initial response team will identify further experts from the Linux
+kernel developer community as needed and inform the disclosing party about
+their participation. Bringing in experts can happen at any time of the
+development process and often needs to be handled in a timely manner.
+
+Coordinated release
+"""""""""""""""""""
+
+The involved parties will negotiate the date and time where the embargo
+ends. At that point the prepared mitigations are integrated into the
+relevant kernel trees and published.
+
+While we understand that hardware security issues need coordinated embargo
+time, the embargo time should be constrained to the minimum time which is
+required for all involved parties to develop, test and prepare the
+mitigations. Extending embargo time artificially to meet conference talk
+dates or other non-technical reasons is creating more work and burden for
+the involved developers and response teams as the patches need to be kept
+up to date in order to follow the ongoing upstream kernel development,
+which might create conflicting changes.
+
+CVE assignment
+""""""""""""""
+
+Neither the hardware security team nor the initial response team assign
+CVEs, nor are CVEs required for the development process. If CVEs are
+provided by the disclosing party they can be used for documentation
+purposes.
+
+Process ambassadors
+-------------------
+
+For assistance with this process we have established ambassadors in various
+organizations, who can answer questions about or provide guidance on the
+reporting process and further handling. Ambassadors are not involved in the
+disclosure of a particular issue, unless requested by a response team or by
+an involved disclosed party. The current ambassadors list:
+
+  ============= ========================================================
+  ARM
+  AMD
+  IBM
+  Intel
+  Qualcomm     Trilok Soni <tsoni@codeaurora.org>
+
+  Microsoft    Sasha Levin <sashal@kernel.org>
+  VMware
+  Xen          Andrew Cooper <andrew.cooper3@citrix.com>
+
+  Canonical    Tyler Hicks <tyhicks@canonical.com>
+  Debian       Ben Hutchings <ben@decadent.org.uk>
+  Oracle       Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+  Red Hat      Josh Poimboeuf <jpoimboe@redhat.com>
+  SUSE         Jiri Kosina <jkosina@suse.cz>
+
+  Amazon
+  Google       Kees Cook <keescook@chromium.org>
+  ============= ========================================================
+
+If you want your organization to be added to the ambassadors list, please
+contact the hardware security team. The nominated ambassador has to
+understand and support our process fully and is ideally well connected in
+the Linux kernel community.
+
+Encrypted mailing-lists
+-----------------------
+
+We use encrypted mailing-lists for communication. The operating principle
+of these lists is that email sent to the list is encrypted either with the
+list's PGP key or with the list's S/MIME certificate. The mailing-list
+software decrypts the email and re-encrypts it individually for each
+subscriber with the subscriber's PGP key or S/MIME certificate. Details
+about the mailing-list software and the setup which is used to ensure the
+security of the lists and protection of the data can be found here:
+https://www.kernel.org/....
+
+List keys
+^^^^^^^^^
+
+For initial contact see :ref:`Contact`. For incident specific mailing-lists
+the key and S/MIME certificate are conveyed to the subscribers by email
+sent from the specific list.
+
+Subscription to incident specific lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Subscription is handled by the response teams. Disclosed parties who want
+to participate in the communication send a list of potential subscribers to
+the response team so the response team can validate subscription requests.
+
+Each subscriber needs to send a subscription request to the response team
+by email. The email must be signed with the subscriber's PGP key or S/MIME
+certificate. If a PGP key is used, it must be available from a public key
+server and is ideally connected to the Linux kernel's PGP web of trust. See
+also: https://www.kernel.org/signature.html.
+
+The response team verifies that the subscriber request is valid and adds
+the subscriber to the list. After subscription the subscriber will receive
+email from the mailing-list which is signed either with the list's PGP key
+or the list's S/MIME certificate. The subscriber's email client can extract
+the PGP key or the S/MIME certificate from the signature so the subscriber
+can send encrypted email to the list.
+
index 878ebfd..e2c9ffc 100644 (file)
@@ -45,6 +45,7 @@ Other guides to the community that are of interest to most developers are:
    submit-checklist
    kernel-docs
    deprecated
+   embargoed-hardware-issues
 
 These are some overall technical guides that have been put here for now for
 lack of a better place.
index 1b73fea..14b1492 100644 (file)
@@ -18,7 +18,7 @@ The following 64-byte header is present in decompressed Linux kernel image.
        u32 res1  = 0;            /* Reserved */
        u64 res2  = 0;            /* Reserved */
        u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
-       u32 res3;                 /* Reserved for additional RISC-V specific header */
+       u32 magic2 = 0x56534905;  /* Magic number 2, little endian, "RSC\x05" */
        u32 res4;                 /* Reserved for PE COFF offset */
 
 This header format is compliant with PE/COFF header and largely inspired from
@@ -37,13 +37,14 @@ Notes:
        Bits 16:31 - Major version
 
   This preserves compatibility across newer and older version of the header.
-  The current version is defined as 0.1.
+  The current version is defined as 0.2.
 
-- res3 is reserved for offset to any other additional fields. This makes the
-  header extendible in future. One example would be to accommodate ISA
-  extension for RISC-V in future. For current version, it is set to be zero.
+- The "magic" field is deprecated as of version 0.2.  In a future
+  release, it may be removed.  This originally should have matched up
+  with the ARM64 header "magic" field, but unfortunately does not.
+  The "magic2" field replaces it, matching up with the ARM64 header.
 
-- In current header, the flag field has only one field.
+- In current header, the flags field has only one field.
        Bit 0: Kernel endianness. 1 if BE, 0 if LE.
 
 - Image size is mandatory for boot loader to load kernel image. Booting will
index 3296533..487852f 100644 (file)
@@ -6,3 +6,4 @@ Trusted Platform Module documentation
 
    tpm_vtpm_proxy
    xen-tpmfront
+   tpm_ftpm_tee
diff --git a/Documentation/security/tpm/tpm_ftpm_tee.rst b/Documentation/security/tpm/tpm_ftpm_tee.rst
new file mode 100644 (file)
index 0000000..8c2bae1
--- /dev/null
@@ -0,0 +1,27 @@
+=============================================
+Firmware TPM Driver
+=============================================
+
+This document describes the firmware Trusted Platform Module (fTPM)
+device driver.
+
+Introduction
+============
+
+This driver is a shim for firmware implemented in ARM's TrustZone
+environment. The driver allows programs to interact with the TPM in the same
+way they would interact with a hardware TPM.
+
+Design
+======
+
+The driver acts as a thin layer that passes commands to and from a TPM
+implemented in firmware. The driver itself doesn't contain much logic and is
+used more like a dumb pipe between firmware and kernel/userspace.
+
+The firmware itself is based on the following paper:
+https://www.microsoft.com/en-us/research/wp-content/uploads/2017/06/ftpm1.pdf
+
+When the driver is loaded it will expose ``/dev/tpmX`` character devices to
+userspace which will enable userspace to communicate with the firmware TPM
+through this device.
index d3b6f28..1dc4955 100644 (file)
@@ -183,7 +183,7 @@ M:  Realtek linux nic maintainers <nic_swsd@realtek.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/realtek/r8169.c
+F:     drivers/net/ethernet/realtek/r8169*
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
 
-ADS1015 HARDWARE MONITOR DRIVER
-M:     Dirk Eibach <eibach@gdsys.de>
-L:     linux-hwmon@vger.kernel.org
-S:     Maintained
-F:     Documentation/hwmon/ads1015.rst
-F:     drivers/hwmon/ads1015.c
-F:     include/linux/platform_data/ads1015.h
-
 ADT746X FAN DRIVER
 M:     Colin Leroy <colin@colino.net>
 S:     Maintained
@@ -683,7 +675,7 @@ S:  Maintained
 F:     drivers/crypto/sunxi-ss/
 
 ALLWINNER VPU DRIVER
-M:     Maxime Ripard <maxime.ripard@bootlin.com>
+M:     Maxime Ripard <mripard@kernel.org>
 M:     Paul Kocialkowski <paul.kocialkowski@bootlin.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
@@ -1350,8 +1342,7 @@ M:        Will Deacon <will@kernel.org>
 R:     Robin Murphy <robin.murphy@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/iommu/arm-smmu.c
-F:     drivers/iommu/arm-smmu-v3.c
+F:     drivers/iommu/arm-smmu*
 F:     drivers/iommu/io-pgtable-arm.c
 F:     drivers/iommu/io-pgtable-arm-v7s.c
 
@@ -1408,7 +1399,7 @@ S:        Maintained
 F:     drivers/clk/sunxi/
 
 ARM/Allwinner sunXi SoC support
-M:     Maxime Ripard <maxime.ripard@bootlin.com>
+M:     Maxime Ripard <mripard@kernel.org>
 M:     Chen-Yu Tsai <wens@csie.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -3548,7 +3539,7 @@ F:        Documentation/filesystems/caching/cachefiles.txt
 F:     fs/cachefiles/
 
 CADENCE MIPI-CSI2 BRIDGES
-M:     Maxime Ripard <maxime.ripard@bootlin.com>
+M:     Maxime Ripard <mripard@kernel.org>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/cdns,*.txt
@@ -4261,6 +4252,14 @@ S:       Supported
 F:     drivers/cpuidle/cpuidle-exynos.c
 F:     arch/arm/mach-exynos/pm.c
 
+CPUIDLE DRIVER - ARM PSCI
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M:     Sudeep Holla <sudeep.holla@arm.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+S:     Supported
+F:     drivers/cpuidle/cpuidle-psci.c
+
 CPU IDLE TIME MANAGEMENT FRAMEWORK
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
@@ -5266,7 +5265,7 @@ F:        include/linux/vga*
 
 DRM DRIVERS AND MISC GPU PATCHES
 M:     Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
-M:     Maxime Ripard <maxime.ripard@bootlin.com>
+M:     Maxime Ripard <mripard@kernel.org>
 M:     Sean Paul <sean@poorly.run>
 W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 S:     Maintained
@@ -5279,7 +5278,7 @@ F:        include/uapi/drm/drm*
 F:     include/linux/vga*
 
 DRM DRIVERS FOR ALLWINNER A10
-M:     Maxime Ripard  <maxime.ripard@bootlin.com>
+M:     Maxime Ripard <mripard@kernel.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/sun4i/
@@ -5732,6 +5731,11 @@ S:       Supported
 F:     drivers/edac/aspeed_edac.c
 F:     Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
 
+EDAC-BLUEFIELD
+M:     Shravan Kumar Ramani <sramani@mellanox.com>
+S:     Supported
+F:     drivers/edac/bluefield_edac.c
+
 EDAC-CALXEDA
 M:     Robert Richter <rric@kernel.org>
 L:     linux-edac@vger.kernel.org
@@ -5756,10 +5760,11 @@ F:      drivers/edac/thunderx_edac*
 EDAC-CORE
 M:     Borislav Petkov <bp@alien8.de>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
+M:     Tony Luck <tony.luck@intel.com>
 R:     James Morse <james.morse@arm.com>
+R:     Robert Richter <rrichter@marvell.com>
 L:     linux-edac@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
 S:     Supported
 F:     Documentation/admin-guide/ras.rst
 F:     Documentation/driver-api/edac.rst
@@ -6036,7 +6041,7 @@ M:        Florian Fainelli <f.fainelli@gmail.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     Documentation/ABI/testing/sysfs-bus-mdio
+F:     Documentation/ABI/testing/sysfs-class-net-phydev
 F:     Documentation/devicetree/bindings/net/ethernet-phy.yaml
 F:     Documentation/devicetree/bindings/net/mdio*
 F:     Documentation/networking/phy.rst
@@ -6302,15 +6307,6 @@ S:       Odd Fixes
 L:     linux-block@vger.kernel.org
 F:     drivers/block/floppy.c
 
-FMC SUBSYSTEM
-M:     Alessandro Rubini <rubini@gnudd.com>
-W:     http://www.ohwr.org/projects/fmc-bus
-S:     Supported
-F:     drivers/fmc/
-F:     include/linux/fmc*.h
-F:     include/linux/ipmi-fru.h
-K:     fmc_d.*register
-
 FPGA MANAGER FRAMEWORK
 M:     Moritz Fischer <mdf@kernel.org>
 L:     linux-fpga@vger.kernel.org
@@ -6410,8 +6406,17 @@ M:       Frank Li <Frank.li@nxp.com>
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
 F:     drivers/perf/fsl_imx8_ddr_perf.c
+F:     Documentation/admin-guide/perf/imx-ddr.rst
 F:     Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt
 
+FREESCALE IMX I2C DRIVER
+M:     Oleksij Rempel <o.rempel@pengutronix.de>
+R:     Pengutronix Kernel Team <kernel@pengutronix.de>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     drivers/i2c/busses/i2c-imx.c
+F:     Documentation/devicetree/bindings/i2c/i2c-imx.txt
+
 FREESCALE IMX LPI2C DRIVER
 M:     Dong Aisheng <aisheng.dong@nxp.com>
 L:     linux-i2c@vger.kernel.org
@@ -6695,6 +6700,13 @@ W:       https://linuxtv.org
 S:     Maintained
 F:     drivers/media/radio/radio-gemtek*
 
+GENERIC ARCHITECTURE TOPOLOGY
+M:     Sudeep Holla <sudeep.holla@arm.com>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/base/arch_topology.c
+F:     include/linux/arch_topology.h
+
 GENERIC GPIO I2C DRIVER
 M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
 S:     Supported
@@ -7423,7 +7435,7 @@ F:        drivers/net/hyperv/
 F:     drivers/scsi/storvsc_drv.c
 F:     drivers/uio/uio_hv_generic.c
 F:     drivers/video/fbdev/hyperv_fb.c
-F:     drivers/iommu/hyperv_iommu.c
+F:     drivers/iommu/hyperv-iommu.c
 F:     net/vmw_vsock/hyperv_transport.c
 F:     include/clocksource/hyperv_timer.h
 F:     include/linux/hyperv.h
@@ -7476,7 +7488,7 @@ I2C MV64XXX MARVELL AND ALLWINNER DRIVER
 M:     Gregory CLEMENT <gregory.clement@bootlin.com>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
+F:     Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
 F:     drivers/i2c/busses/i2c-mv64xxx.c
 
 I2C OVER PARALLEL PORT
@@ -8035,6 +8047,13 @@ T:       git git://git.code.sf.net/p/intel-sas/isci
 S:     Supported
 F:     drivers/scsi/isci/
 
+INTEL CPU family model numbers
+M:     Tony Luck <tony.luck@intel.com>
+M:     x86@kernel.org
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+F:     arch/x86/include/asm/intel-family.h
+
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Jani Nikula <jani.nikula@linux.intel.com>
 M:     Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
@@ -8341,12 +8360,6 @@ F:       Documentation/x86/intel_txt.rst
 F:     include/linux/tboot.h
 F:     arch/x86/kernel/tboot.c
 
-INTEL-MID GPIO DRIVER
-M:     David Cohen <david.a.cohen@linux.intel.com>
-L:     linux-gpio@vger.kernel.org
-S:     Maintained
-F:     drivers/gpio/gpio-intel-mid.c
-
 INTERCONNECT API
 M:     Georgi Djakov <georgi.djakov@linaro.org>
 L:     linux-pm@vger.kernel.org
@@ -8371,12 +8384,6 @@ L:       linux-mips@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/sgi/ioc3-eth.c
 
-IOC3 SERIAL DRIVER
-M:     Pat Gefre <pfg@sgi.com>
-L:     linux-serial@vger.kernel.org
-S:     Maintained
-F:     drivers/tty/serial/ioc3_serial.c
-
 IOMAP FILESYSTEM LIBRARY
 M:     Christoph Hellwig <hch@infradead.org>
 M:     Darrick J. Wong <darrick.wong@oracle.com>
@@ -8386,7 +8393,6 @@ L:        linux-xfs@vger.kernel.org
 L:     linux-fsdevel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 S:     Supported
-F:     fs/iomap.c
 F:     fs/iomap/
 F:     include/linux/iomap.h
 
@@ -8411,11 +8417,6 @@ S:       Maintained
 F:     fs/io_uring.c
 F:     include/uapi/linux/io_uring.h
 
-IP MASQUERADING
-M:     Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
-S:     Maintained
-F:     net/ipv4/netfilter/ipt_MASQUERADE.c
-
 IPMI SUBSYSTEM
 M:     Corey Minyard <minyard@acm.org>
 L:     openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
@@ -8789,14 +8790,6 @@ F:       virt/kvm/*
 F:     tools/kvm/
 F:     tools/testing/selftests/kvm/
 
-KERNEL VIRTUAL MACHINE FOR AMD-V (KVM/amd)
-M:     Joerg Roedel <joro@8bytes.org>
-L:     kvm@vger.kernel.org
-W:     http://www.linux-kvm.org/
-S:     Maintained
-F:     arch/x86/include/asm/svm.h
-F:     arch/x86/kvm/svm.c
-
 KERNEL VIRTUAL MACHINE FOR ARM/ARM64 (KVM/arm, KVM/arm64)
 M:     Marc Zyngier <maz@kernel.org>
 R:     James Morse <james.morse@arm.com>
@@ -8839,7 +8832,7 @@ M:        Christian Borntraeger <borntraeger@de.ibm.com>
 M:     Janosch Frank <frankja@linux.ibm.com>
 R:     David Hildenbrand <david@redhat.com>
 R:     Cornelia Huck <cohuck@redhat.com>
-L:     linux-s390@vger.kernel.org
+L:     kvm@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
 S:     Supported
@@ -8854,6 +8847,11 @@ F:       tools/testing/selftests/kvm/*/s390x/
 KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
 M:     Paolo Bonzini <pbonzini@redhat.com>
 M:     Radim Krčmář <rkrcmar@redhat.com>
+R:     Sean Christopherson <sean.j.christopherson@intel.com>
+R:     Vitaly Kuznetsov <vkuznets@redhat.com>
+R:     Wanpeng Li <wanpengli@tencent.com>
+R:     Jim Mattson <jmattson@google.com>
+R:     Joerg Roedel <joro@8bytes.org>
 L:     kvm@vger.kernel.org
 W:     http://www.linux-kvm.org
 T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
@@ -8861,8 +8859,12 @@ S:       Supported
 F:     arch/x86/kvm/
 F:     arch/x86/kvm/*/
 F:     arch/x86/include/uapi/asm/kvm*
+F:     arch/x86/include/uapi/asm/vmx.h
+F:     arch/x86/include/uapi/asm/svm.h
 F:     arch/x86/include/asm/kvm*
 F:     arch/x86/include/asm/pvclock-abi.h
+F:     arch/x86/include/asm/svm.h
+F:     arch/x86/include/asm/vmx.h
 F:     arch/x86/kernel/kvm.c
 F:     arch/x86/kernel/kvmclock.c
 
@@ -8894,7 +8896,7 @@ F:        security/keys/encrypted-keys/
 
 KEYS-TRUSTED
 M:     James Bottomley <jejb@linux.ibm.com>
-M:      Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 M:     Mimi Zohar <zohar@linux.ibm.com>
 L:     linux-integrity@vger.kernel.org
 L:     keyrings@vger.kernel.org
@@ -9190,6 +9192,18 @@ F:       include/linux/nd.h
 F:     include/linux/libnvdimm.h
 F:     include/uapi/linux/ndctl.h
 
+LICENSES and SPDX stuff
+M:     Thomas Gleixner <tglx@linutronix.de>
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+L:     linux-spdx@vger.kernel.org
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/spdx.git
+F:     COPYING
+F:     Documentation/process/license-rules.rst
+F:     LICENSES/
+F:     scripts/spdxcheck-test.sh
+F:     scripts/spdxcheck.py
+
 LIGHTNVM PLATFORM SUPPORT
 M:     Matias Bjorling <mb@lightnvm.io>
 W:     http://github/OpenChannelSSD
@@ -11029,7 +11043,7 @@ NET_FAILOVER MODULE
 M:     Sridhar Samudrala <sridhar.samudrala@intel.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     driver/net/net_failover.c
+F:     drivers/net/net_failover.c
 F:     include/net/net_failover.h
 F:     Documentation/networking/net_failover.rst
 
@@ -14426,6 +14440,7 @@ F:      drivers/net/phy/phylink.c
 F:     drivers/net/phy/sfp*
 F:     include/linux/phylink.h
 F:     include/linux/sfp.h
+K:     phylink
 
 SGI GRU DRIVER
 M:     Dimitri Sivanich <sivanich@sgi.com>
@@ -14831,9 +14846,9 @@ F:      include/linux/arm_sdei.h
 F:     include/uapi/linux/arm_sdei.h
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
-M:     Shaohua Li <shli@kernel.org>
+M:     Song Liu <song@kernel.org>
 L:     linux-raid@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shli/md.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git
 S:     Supported
 F:     drivers/md/Makefile
 F:     drivers/md/Kconfig
@@ -17203,6 +17218,7 @@ F:      Documentation/power/regulator/
 F:     drivers/regulator/
 F:     include/dt-bindings/regulator/
 F:     include/linux/regulator/
+K:     regulator_get_optional
 
 VRF
 M:     David Ahern <dsa@cumulusnetworks.com>
@@ -17639,8 +17655,7 @@ F:      include/uapi/linux/dqblk_xfs.h
 F:     include/uapi/linux/fsmap.h
 
 XILINX AXI ETHERNET DRIVER
-M:     Anirudha Sarangi <anirudh@xilinx.com>
-M:     John Linn <John.Linn@xilinx.com>
+M:     Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
 S:     Maintained
 F:     drivers/net/ethernet/xilinx/xilinx_axienet*
 
index 1b23f95..4262ef9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION =
 NAME = Bobtail Squid
 
 # *DOCUMENTATION*
@@ -913,6 +913,10 @@ ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
 LDFLAGS_vmlinux        += $(call ld-option, -X,)
 endif
 
+ifeq ($(CONFIG_RELR),y)
+LDFLAGS_vmlinux        += --pack-dyn-relocs=relr
+endif
+
 # insure the checker run with the right endianness
 CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian)
 
index a7b57dd..71d9ae0 100644 (file)
@@ -18,6 +18,9 @@ config KEXEC_CORE
        select CRASH_CORE
        bool
 
+config KEXEC_ELF
+       bool
+
 config HAVE_IMA_KEXEC
        bool
 
@@ -925,6 +928,20 @@ config LOCK_EVENT_COUNTS
          the chance of application behavior change because of timing
          differences. The counts are reported via debugfs.
 
+# Select if the architecture has support for applying RELR relocations.
+config ARCH_HAS_RELR
+       bool
+
+config RELR
+       bool "Use RELR relocation packing"
+       depends on ARCH_HAS_RELR && TOOLS_SUPPORT_RELR
+       default y
+       help
+         Store the kernel's dynamic relocations in the RELR relocation packing
+         format. Requires a compatible linker (LLD supports this feature), as
+         well as compatible NM and OBJCOPY utilities (llvm-nm and llvm-objcopy
+         are compatible).
+
 source "kernel/gcov/Kconfig"
 
 source "scripts/gcc-plugins/Kconfig"
index a83c4f5..8483a86 100644 (file)
@@ -12,3 +12,6 @@ dtb-y := $(builtindtb-y).dtb
 # for CONFIG_OF_ALL_DTBS test
 dtstree        := $(srctree)/$(src)
 dtb-   := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
+
+# board-specific dtc flags
+DTC_FLAGS_hsdk += --pad 20
index f5ae394..41b16f2 100644 (file)
 
 .macro FAKE_RET_FROM_EXCPN
        lr      r9, [status32]
-       bic     r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK)
+       bic     r9, r9, STATUS_AE_MASK
        or      r9, r9, STATUS_IE_MASK
        kflag   r9
 .endm
index a0eeb9f..d9ee43c 100644 (file)
 #else  /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_ARC_HAS_ICCM
-#define __arcfp_code __attribute__((__section__(".text.arcfp")))
+#define __arcfp_code __section(.text.arcfp)
 #else
-#define __arcfp_code __attribute__((__section__(".text")))
+#define __arcfp_code __section(.text)
 #endif
 
 #ifdef CONFIG_ARC_HAS_DCCM
-#define __arcfp_data __attribute__((__section__(".data.arcfp")))
+#define __arcfp_data __section(.data.arcfp)
 #else
-#define __arcfp_data __attribute__((__section__(".data")))
+#define __arcfp_data __section(.data)
 #endif
 
 #endif /* __ASSEMBLY__ */
index 8ac0e2a..73746ed 100644 (file)
@@ -53,8 +53,7 @@ extern const struct machine_desc __arch_info_begin[], __arch_info_end[];
  */
 #define MACHINE_START(_type, _name)                    \
 static const struct machine_desc __mach_desc_##_type   \
-__used                                                 \
-__attribute__((__section__(".arch.info.init"))) = {    \
+__used __section(.arch.info.init) = {                  \
        .name           = _name,
 
 #define MACHINE_END                            \
index 18b493d..abf9398 100644 (file)
@@ -202,8 +202,8 @@ static void idu_set_dest(unsigned int cmn_irq, unsigned int cpu_mask)
        __mcip_cmd_data(CMD_IDU_SET_DEST, cmn_irq, cpu_mask);
 }
 
-static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl,
-                          unsigned int distr)
+static void idu_set_mode(unsigned int cmn_irq, bool set_lvl, unsigned int lvl,
+                        bool set_distr, unsigned int distr)
 {
        union {
                unsigned int word;
@@ -212,8 +212,11 @@ static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl,
                };
        } data;
 
-       data.distr = distr;
-       data.lvl = lvl;
+       data.word = __mcip_cmd_read(CMD_IDU_READ_MODE, cmn_irq);
+       if (set_distr)
+               data.distr = distr;
+       if (set_lvl)
+               data.lvl = lvl;
        __mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word);
 }
 
@@ -240,6 +243,25 @@ static void idu_irq_unmask(struct irq_data *data)
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
 }
 
+static void idu_irq_ack(struct irq_data *data)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+       __mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq);
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+}
+
+static void idu_irq_mask_ack(struct irq_data *data)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+       __mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 1);
+       __mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq);
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+}
+
 static int
 idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
                     bool force)
@@ -263,13 +285,36 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
        else
                distribution_mode = IDU_M_DISTRI_RR;
 
-       idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode);
+       idu_set_mode(data->hwirq, false, 0, true, distribution_mode);
 
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
 
        return IRQ_SET_MASK_OK;
 }
 
+static int idu_irq_set_type(struct irq_data *data, u32 type)
+{
+       unsigned long flags;
+
+       /*
+        * ARCv2 IDU HW does not support inverse polarity, so these are the
+        * only interrupt types supported.
+        */
+       if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+               return -EINVAL;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+
+       idu_set_mode(data->hwirq, true,
+                    type & IRQ_TYPE_EDGE_RISING ? IDU_M_TRIG_EDGE :
+                                                  IDU_M_TRIG_LEVEL,
+                    false, 0);
+
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+
+       return 0;
+}
+
 static void idu_irq_enable(struct irq_data *data)
 {
        /*
@@ -289,7 +334,10 @@ static struct irq_chip idu_irq_chip = {
        .name                   = "MCIP IDU Intc",
        .irq_mask               = idu_irq_mask,
        .irq_unmask             = idu_irq_unmask,
+       .irq_ack                = idu_irq_ack,
+       .irq_mask_ack           = idu_irq_mask_ack,
        .irq_enable             = idu_irq_enable,
+       .irq_set_type           = idu_irq_set_type,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = idu_irq_set_affinity,
 #endif
@@ -317,7 +365,7 @@ static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t
 }
 
 static const struct irq_domain_ops idu_irq_ops = {
-       .xlate  = irq_domain_xlate_onecell,
+       .xlate  = irq_domain_xlate_onetwocell,
        .map    = idu_irq_map,
 };
 
index c2663fc..dc05a63 100644 (file)
@@ -572,6 +572,7 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end,
 #else
                BUILD_BUG_ON(sizeof(u32) != sizeof(value));
 #endif
+               /* Fall through */
        case DW_EH_PE_native:
                if (end < (const void *)(ptr.pul + 1))
                        return 0;
@@ -826,7 +827,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
                        case DW_CFA_def_cfa:
                                state->cfa.reg = get_uleb128(&ptr.p8, end);
                                unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
-                               /*nobreak*/
+                               /* fall through */
                        case DW_CFA_def_cfa_offset:
                                state->cfa.offs = get_uleb128(&ptr.p8, end);
                                unw_debug("cfa_def_cfa_offset: 0x%lx ",
@@ -834,7 +835,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
                                break;
                        case DW_CFA_def_cfa_sf:
                                state->cfa.reg = get_uleb128(&ptr.p8, end);
-                               /*nobreak */
+                               /* fall through */
                        case DW_CFA_def_cfa_offset_sf:
                                state->cfa.offs = get_sleb128(&ptr.p8, end)
                                    * state->dataAlign;
index 62c210e..70a3fbe 100644 (file)
@@ -101,7 +101,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
        if (is_isa_arcv2() && ioc_enable && coherent)
                dev->dma_coherent = true;
 
-       dev_info(dev, "use %sncoherent DMA ops\n",
+       dev_info(dev, "use %scoherent DMA ops\n",
                 dev->dma_coherent ? "" : "non");
 }
 
index 7dd2dd3..0b961a2 100644 (file)
@@ -6,11 +6,15 @@
  */
 
 #include <linux/init.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
 #include <linux/smp.h>
 #include <asm/arcregs.h>
 #include <asm/io.h>
 #include <asm/mach_desc.h>
 
+int arc_hsdk_axi_dmac_coherent __section(.data) = 0;
+
 #define ARC_CCM_UNUSED_ADDR    0x60000000
 
 static void __init hsdk_init_per_cpu(unsigned int cpu)
@@ -97,6 +101,42 @@ static void __init hsdk_enable_gpio_intc_wire(void)
        iowrite32(GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTEN);
 }
 
+static int __init hsdk_tweak_node_coherency(const char *path, bool coherent)
+{
+       void *fdt = initial_boot_params;
+       const void *prop;
+       int node, ret;
+       bool dt_coh_set;
+
+       node = fdt_path_offset(fdt, path);
+       if (node < 0)
+               goto tweak_fail;
+
+       prop = fdt_getprop(fdt, node, "dma-coherent", &ret);
+       if (!prop && ret != -FDT_ERR_NOTFOUND)
+               goto tweak_fail;
+
+       dt_coh_set = ret != -FDT_ERR_NOTFOUND;
+       ret = 0;
+
+       /* need to remove "dma-coherent" property */
+       if (dt_coh_set && !coherent)
+               ret = fdt_delprop(fdt, node, "dma-coherent");
+
+       /* need to set "dma-coherent" property */
+       if (!dt_coh_set && coherent)
+               ret = fdt_setprop(fdt, node, "dma-coherent", NULL, 0);
+
+       if (ret < 0)
+               goto tweak_fail;
+
+       return 0;
+
+tweak_fail:
+       pr_err("failed to tweak %s to %scoherent\n", path, coherent ? "" : "non");
+       return -EFAULT;
+}
+
 enum hsdk_axi_masters {
        M_HS_CORE = 0,
        M_HS_RTT,
@@ -162,6 +202,39 @@ enum hsdk_axi_masters {
 #define CREG_PAE               ((void __iomem *)(CREG_BASE + 0x180))
 #define CREG_PAE_UPDT          ((void __iomem *)(CREG_BASE + 0x194))
 
+static void __init hsdk_init_memory_bridge_axi_dmac(void)
+{
+       bool coherent = !!arc_hsdk_axi_dmac_coherent;
+       u32 axi_m_slv1, axi_m_oft1;
+
+       /*
+        * Don't tweak memory bridge configuration if we failed to tweak DTB
+        * as we will end up in a inconsistent state.
+        */
+       if (hsdk_tweak_node_coherency("/soc/dmac@80000", coherent))
+               return;
+
+       if (coherent) {
+               axi_m_slv1 = 0x77999999;
+               axi_m_oft1 = 0x76DCBA98;
+       } else {
+               axi_m_slv1 = 0x77777777;
+               axi_m_oft1 = 0x76543210;
+       }
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
+       writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_0));
+       writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_0));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
+
+       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
+       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
+       writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_1));
+       writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_1));
+       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
+}
+
 static void __init hsdk_init_memory_bridge(void)
 {
        u32 reg;
@@ -227,24 +300,14 @@ static void __init hsdk_init_memory_bridge(void)
        writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
 
-       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
-       writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
-       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
-       writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
-       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
-
-       writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
-       writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
-       writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
-       writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
-       writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
-
        writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
        writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
        writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
        writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
 
+       hsdk_init_memory_bridge_axi_dmac();
+
        /*
         * PAE remapping for DMA clients does not work due to an RTL bug, so
         * CREG_PAE register must be programmed to all zeroes, otherwise it
index 1cc8d5f..2ae7f8a 100644 (file)
@@ -7,6 +7,8 @@ config ARM
        select ARCH_HAS_BINFMT_FLAT
        select ARCH_HAS_DEBUG_VIRTUAL if MMU
        select ARCH_HAS_DEVMEM_IS_ALLOWED
+       select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
+       select ARCH_HAS_DMA_MMAP_PGPROT if SWIOTLB
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_KEEPINITRD
@@ -18,6 +20,8 @@ config ARM
        select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
        select ARCH_HAS_STRICT_MODULE_RWX if MMU
+       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if SWIOTLB
+       select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB
        select ARCH_HAS_TEARDOWN_DMA_OPS if MMU
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAVE_CUSTOM_GPIO_H
index ced1a19..46849d6 100644 (file)
                        uart0: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <72>;
                                status = "disabled";
                                dmas = <&edma 26 0>, <&edma 27 0>;
                        uart1: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <73>;
                                status = "disabled";
                                dmas = <&edma 28 0>, <&edma 29 0>;
                        uart2: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <74>;
                                status = "disabled";
                                dmas = <&edma 30 0>, <&edma 31 0>;
                        uart3: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <44>;
                                status = "disabled";
                        };
                        uart4: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <45>;
                                status = "disabled";
                        };
                        uart5: serial@0 {
                                compatible = "ti,am3352-uart", "ti,omap3-uart";
                                clock-frequency = <48000000>;
-                               reg = <0x0 0x2000>;
+                               reg = <0x0 0x1000>;
                                interrupts = <46>;
                                status = "disabled";
                        };
 
                target-module@cc000 {                   /* 0x481cc000, ap 60 46.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
+                       reg = <0xcc020 0x4>;
+                       reg-names = "rev";
                        ti,hwmods = "d_can0";
                        /* Domains (P, C): per_pwrdm, l4ls_clkdm */
                        clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN0_CLKCTRL 0>,
 
                target-module@d0000 {                   /* 0x481d0000, ap 62 42.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
+                       reg = <0xd0020 0x4>;
+                       reg-names = "rev";
                        ti,hwmods = "d_can1";
                        /* Domains (P, C): per_pwrdm, l4ls_clkdm */
                        clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN1_CLKCTRL 0>,
index e5c2f71..fb6b8aa 100644 (file)
                        interrupt-names = "edma3_tcerrint";
                };
 
-               mmc3: mmc@47810000 {
-                       compatible = "ti,omap4-hsmmc";
+               target-module@47810000 {
+                       compatible = "ti,sysc-omap2", "ti,sysc";
                        ti,hwmods = "mmc3";
-                       ti,needs-special-reset;
-                       interrupts = <29>;
-                       reg = <0x47810000 0x1000>;
-                       status = "disabled";
+                       reg = <0x478102fc 0x4>,
+                             <0x47810110 0x4>,
+                             <0x47810114 0x4>;
+                       reg-names = "rev", "sysc", "syss";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET |
+                                        SYSC_OMAP2_AUTOIDLE)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       ti,syss-mask = <1>;
+                       clocks = <&l3s_clkctrl AM3_L3S_MMC3_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x47810000 0x1000>;
+
+                       mmc3: mmc@0 {
+                               compatible = "ti,omap4-hsmmc";
+                               ti,needs-special-reset;
+                               interrupts = <29>;
+                               reg = <0x0 0x1000>;
+                       };
                };
 
                usb: usb@47400000 {
index 55aff4d..848e2a8 100644 (file)
                        interrupt-names = "edma3_tcerrint";
                };
 
-               mmc3: mmc@47810000 {
-                       compatible = "ti,omap4-hsmmc";
-                       reg = <0x47810000 0x1000>;
+               target-module@47810000 {
+                       compatible = "ti,sysc-omap2", "ti,sysc";
                        ti,hwmods = "mmc3";
-                       ti,needs-special-reset;
-                       interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-                       status = "disabled";
+                       reg = <0x478102fc 0x4>,
+                             <0x47810110 0x4>,
+                             <0x47810114 0x4>;
+                       reg-names = "rev", "sysc", "syss";
+                       ti,sysc-mask = <(SYSC_OMAP2_CLOCKACTIVITY |
+                                        SYSC_OMAP2_ENAWAKEUP |
+                                        SYSC_OMAP2_SOFTRESET |
+                                        SYSC_OMAP2_AUTOIDLE)>;
+                       ti,sysc-sidle = <SYSC_IDLE_FORCE>,
+                                       <SYSC_IDLE_NO>,
+                                       <SYSC_IDLE_SMART>;
+                       ti,syss-mask = <1>;
+                       clocks = <&l3s_clkctrl AM4_L3S_MMC3_CLKCTRL 0>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x47810000 0x1000>;
+
+                       mmc3: mmc@0 {
+                               compatible = "ti,omap4-hsmmc";
+                               ti,needs-special-reset;
+                               interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x0 0x1000>;
+                       };
                };
 
                sham: sham@53100000 {
index 989cb60..04bee4f 100644 (file)
 
                target-module@cc000 {                   /* 0x481cc000, ap 50 46.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
+                       reg = <0xcc020 0x4>;
+                       reg-names = "rev";
                        ti,hwmods = "d_can0";
                        /* Domains (P, C): per_pwrdm, l4ls_clkdm */
                        clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN0_CLKCTRL 0>;
 
                target-module@d0000 {                   /* 0x481d0000, ap 52 3a.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
+                       reg = <0xd0020 0x4>;
+                       reg-names = "rev";
                        ti,hwmods = "d_can1";
                        /* Domains (P, C): per_pwrdm, l4ls_clkdm */
                        clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN1_CLKCTRL 0>;
index 1d5e999..0aaacea 100644 (file)
 };
 
 &mmc1 {
-       pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
+       pinctrl-names = "default", "hs";
        pinctrl-0 = <&mmc1_pins_default_no_clk_pu>;
        pinctrl-1 = <&mmc1_pins_hs>;
-       pinctrl-2 = <&mmc1_pins_sdr12>;
-       pinctrl-3 = <&mmc1_pins_sdr25>;
-       pinctrl-4 = <&mmc1_pins_sdr50>;
-       pinctrl-5 = <&mmc1_pins_ddr50_rev20 &mmc1_iodelay_ddr50_conf>;
-       pinctrl-6 = <&mmc1_pins_sdr104 &mmc1_iodelay_sdr104_rev20_conf>;
 };
 
 &mmc2 {
index c65d7f6..ea1c119 100644 (file)
 };
 
 &mmc1 {
-       pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
+       pinctrl-names = "default", "hs";
        pinctrl-0 = <&mmc1_pins_default_no_clk_pu>;
        pinctrl-1 = <&mmc1_pins_hs>;
-       pinctrl-2 = <&mmc1_pins_sdr12>;
-       pinctrl-3 = <&mmc1_pins_sdr25>;
-       pinctrl-4 = <&mmc1_pins_sdr50>;
-       pinctrl-5 = <&mmc1_pins_ddr50 &mmc1_iodelay_ddr_rev20_conf>;
-       pinctrl-6 = <&mmc1_pins_sdr104 &mmc1_iodelay_sdr104_rev20_conf>;
 };
 
 &mmc2 {
index dc5141c..7935d70 100644 (file)
 };
 
 &mmc1 {
-       pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
+       pinctrl-names = "default", "hs";
        pinctrl-0 = <&mmc1_pins_default_no_clk_pu>;
        pinctrl-1 = <&mmc1_pins_hs>;
-       pinctrl-2 = <&mmc1_pins_default>;
-       pinctrl-3 = <&mmc1_pins_hs>;
-       pinctrl-4 = <&mmc1_pins_sdr50>;
-       pinctrl-5 = <&mmc1_pins_ddr50 &mmc1_iodelay_ddr_conf>;
-       pinctrl-6 = <&mmc1_pins_ddr50 &mmc1_iodelay_sdr104_conf>;
 };
 
 &mmc2 {
index d02f5fa..bc76f17 100644 (file)
        };
 };
 
-&gpio7 {
+&gpio7_target {
        ti,no-reset-on-init;
        ti,no-idle-on-init;
 };
 
        bus-width = <4>;
        cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
+       no-1-8-v;
 };
 
 &mmc2 {
index a374b5c..7b113b5 100644 (file)
 };
 
 &mmc1 {
-       pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
+       pinctrl-names = "default", "hs";
        pinctrl-0 = <&mmc1_pins_default>;
        pinctrl-1 = <&mmc1_pins_hs>;
-       pinctrl-2 = <&mmc1_pins_sdr12>;
-       pinctrl-3 = <&mmc1_pins_sdr25>;
-       pinctrl-4 = <&mmc1_pins_sdr50>;
-       pinctrl-5 = <&mmc1_pins_ddr50 &mmc1_iodelay_ddr_rev11_conf>;
-       pinctrl-6 = <&mmc1_pins_sdr104 &mmc1_iodelay_sdr104_rev11_conf>;
        vmmc-supply = <&vdd_3v3>;
        vqmmc-supply = <&ldo1_reg>;
 };
index 4badd21..30c500b 100644 (file)
 };
 
 &mmc1 {
-       pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
+       pinctrl-names = "default", "hs";
        pinctrl-0 = <&mmc1_pins_default>;
        pinctrl-1 = <&mmc1_pins_hs>;
-       pinctrl-2 = <&mmc1_pins_sdr12>;
-       pinctrl-3 = <&mmc1_pins_sdr25>;
-       pinctrl-4 = <&mmc1_pins_sdr50>;
-       pinctrl-5 = <&mmc1_pins_ddr50 &mmc1_iodelay_ddr_rev20_conf>;
-       pinctrl-6 = <&mmc1_pins_sdr104 &mmc1_iodelay_sdr104_rev20_conf>;
        vmmc-supply = <&vdd_3v3>;
        vqmmc-supply = <&ldo1_reg>;
 };
index 714e971..de7f85e 100644 (file)
        phy-supply = <&ldousb_reg>;
 };
 
-&gpio7 {
+&gpio7_target {
        ti,no-reset-on-init;
        ti,no-idle-on-init;
 };
index 23faede..21e5914 100644 (file)
                        };
                };
 
-               target-module@51000 {                   /* 0x48051000, ap 45 2e.0 */
+               gpio7_target: target-module@51000 {             /* 0x48051000, ap 45 2e.0 */
                        compatible = "ti,sysc-omap2", "ti,sysc";
                        ti,hwmods = "gpio7";
                        reg = <0x51000 0x4>,
 
                target-module@80000 {                   /* 0x48480000, ap 31 16.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       reg = <0x80000 0x4>;
+                       reg = <0x80020 0x4>;
                        reg-names = "rev";
                        clocks = <&l4per2_clkctrl DRA7_L4PER2_DCAN2_CLKCTRL 0>;
                        clock-names = "fck";
 
                target-module@c000 {                    /* 0x4ae3c000, ap 30 04.0 */
                        compatible = "ti,sysc-omap4", "ti,sysc";
-                       reg = <0xc000 0x4>;
+                       reg = <0xc020 0x4>;
                        reg-names = "rev";
                        clocks = <&wkupaon_clkctrl DRA7_WKUPAON_DCAN1_CLKCTRL 0>;
                        clock-names = "fck";
index 28ebb4e..214b9e6 100644 (file)
@@ -32,7 +32,7 @@
  *
  * Datamanual Revisions:
  *
- * AM572x Silicon Revision 2.0: SPRS953B, Revised November 2016
+ * AM572x Silicon Revision 2.0: SPRS953F, Revised May 2019
  * AM572x Silicon Revision 1.1: SPRS915R, Revised November 2016
  *
  */
 
        mmc3_pins_default: mmc3_pins_default {
                pinctrl-single,pins = <
-                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
-                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
-                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
-                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
-                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
-                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
+                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
+                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
+                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
+                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
+                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
+                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
                >;
        };
 
        mmc3_pins_hs: mmc3_pins_hs {
                pinctrl-single,pins = <
-                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
-                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
-                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
-                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
-                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
-                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
+                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
+                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
+                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
+                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
+                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
+                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
                >;
        };
 
        mmc3_pins_sdr12: mmc3_pins_sdr12 {
                pinctrl-single,pins = <
-                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
-                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
-                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
-                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
-                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
-                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
+                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
+                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
+                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
+                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
+                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
+                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
                >;
        };
 
        mmc3_pins_sdr25: mmc3_pins_sdr25 {
                pinctrl-single,pins = <
-                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
-                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
-                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
-                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
-                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
-                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
+                       DRA7XX_CORE_IOPAD(0x377c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_clk.mmc3_clk */
+                       DRA7XX_CORE_IOPAD(0x3780, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_cmd.mmc3_cmd */
+                       DRA7XX_CORE_IOPAD(0x3784, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat0.mmc3_dat0 */
+                       DRA7XX_CORE_IOPAD(0x3788, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat1.mmc3_dat1 */
+                       DRA7XX_CORE_IOPAD(0x378c, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat2.mmc3_dat2 */
+                       DRA7XX_CORE_IOPAD(0x3790, (PIN_INPUT_PULLUP | MODE_SELECT | MUX_MODE0)) /* mmc3_dat3.mmc3_dat3 */
                >;
        };
 
index 3fa0cbe..0f3870d 100644 (file)
                reg = <0>;
        };
 
-       n25q128a13_2: flash@1 {
+       n25q128a13_2: flash@2 {
                compatible = "n25q128a13", "jedec,spi-nor";
                #address-cells = <1>;
                #size-cells = <1>;
                spi-max-frequency = <66000000>;
                spi-rx-bus-width = <2>;
-               reg = <1>;
+               reg = <2>;
        };
 };
 
index 2a786f5..8a0fae9 100644 (file)
@@ -5,26 +5,6 @@
 #ifdef CONFIG_ARM_CPU_TOPOLOGY
 
 #include <linux/cpumask.h>
-
-struct cputopo_arm {
-       int thread_id;
-       int core_id;
-       int socket_id;
-       cpumask_t thread_sibling;
-       cpumask_t core_sibling;
-};
-
-extern struct cputopo_arm cpu_topology[NR_CPUS];
-
-#define topology_physical_package_id(cpu)      (cpu_topology[cpu].socket_id)
-#define topology_core_id(cpu)          (cpu_topology[cpu].core_id)
-#define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
-#define topology_sibling_cpumask(cpu)  (&cpu_topology[cpu].thread_sibling)
-
-void init_cpu_topology(void);
-void store_cpu_topology(unsigned int cpuid);
-const struct cpumask *cpu_coregroup_mask(int cpu);
-
 #include <linux/arch_topology.h>
 
 /* Replace task scheduler's default frequency-invariant accounting */
index d17cb1e..5b9faba 100644 (file)
@@ -177,17 +177,6 @@ static inline void parse_dt_topology(void) {}
 static inline void update_cpu_capacity(unsigned int cpuid) {}
 #endif
 
- /*
- * cpu topology table
- */
-struct cputopo_arm cpu_topology[NR_CPUS];
-EXPORT_SYMBOL_GPL(cpu_topology);
-
-const struct cpumask *cpu_coregroup_mask(int cpu)
-{
-       return &cpu_topology[cpu].core_sibling;
-}
-
 /*
  * The current assumption is that we can power gate each core independently.
  * This will be superseded by DT binding once available.
@@ -197,32 +186,6 @@ const struct cpumask *cpu_corepower_mask(int cpu)
        return &cpu_topology[cpu].thread_sibling;
 }
 
-static void update_siblings_masks(unsigned int cpuid)
-{
-       struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
-       int cpu;
-
-       /* update core and thread sibling masks */
-       for_each_possible_cpu(cpu) {
-               cpu_topo = &cpu_topology[cpu];
-
-               if (cpuid_topo->socket_id != cpu_topo->socket_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
-               if (cpu != cpuid)
-                       cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
-
-               if (cpuid_topo->core_id != cpu_topo->core_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
-               if (cpu != cpuid)
-                       cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
-       }
-       smp_wmb();
-}
-
 /*
  * store_cpu_topology is called at boot when only one cpu is running
  * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
@@ -230,7 +193,7 @@ static void update_siblings_masks(unsigned int cpuid)
  */
 void store_cpu_topology(unsigned int cpuid)
 {
-       struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
+       struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
        unsigned int mpidr;
 
        /* If the cpu topology has been already set, just return */
@@ -250,12 +213,12 @@ void store_cpu_topology(unsigned int cpuid)
                        /* core performance interdependency */
                        cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
                        cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-                       cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
+                       cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
                } else {
                        /* largely independent cores */
                        cpuid_topo->thread_id = -1;
                        cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-                       cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+                       cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
                }
        } else {
                /*
@@ -265,7 +228,7 @@ void store_cpu_topology(unsigned int cpuid)
                 */
                cpuid_topo->thread_id = -1;
                cpuid_topo->core_id = 0;
-               cpuid_topo->socket_id = -1;
+               cpuid_topo->package_id = -1;
        }
 
        update_siblings_masks(cpuid);
@@ -275,7 +238,7 @@ void store_cpu_topology(unsigned int cpuid)
        pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
                cpuid, cpu_topology[cpuid].thread_id,
                cpu_topology[cpuid].core_id,
-               cpu_topology[cpuid].socket_id, mpidr);
+               cpu_topology[cpuid].package_id, mpidr);
 }
 
 static inline int cpu_corepower_flags(void)
@@ -298,18 +261,7 @@ static struct sched_domain_topology_level arm_topology[] = {
  */
 void __init init_cpu_topology(void)
 {
-       unsigned int cpu;
-
-       /* init core mask and capacity */
-       for_each_possible_cpu(cpu) {
-               struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
-
-               cpu_topo->thread_id = -1;
-               cpu_topo->core_id =  -1;
-               cpu_topo->socket_id = -1;
-               cpumask_clear(&cpu_topo->core_sibling);
-               cpumask_clear(&cpu_topo->thread_sibling);
-       }
+       reset_cpu_topology();
        smp_wmb();
 
        parse_dt_topology();
index 1d5210e..5829252 100644 (file)
@@ -66,7 +66,7 @@ for_each_frame:       tst     frame, mask             @ Check for address exceptions
 
 1003:          ldr     r2, [sv_pc, #-4]        @ if stmfd sp!, {args} exists,
                ldr     r3, .Ldsi+4             @ adjust saved 'pc' back one
-               teq     r3, r2, lsr #10         @ instruction
+               teq     r3, r2, lsr #11         @ instruction
                subne   r0, sv_pc, #4           @ allow for mov
                subeq   r0, sv_pc, #8           @ allow for mov + stmia
 
index 1f0da76..7b7280c 100644 (file)
@@ -103,7 +103,7 @@ static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
 };
 
 static struct gpiod_lookup_table edb93xx_spi_cs_gpio_table = {
-       .dev_id = "ep93xx-spi.0",
+       .dev_id = "spi0",
        .table = {
                GPIO_LOOKUP("A", 6, "cs", GPIO_ACTIVE_LOW),
                { },
index e2658e2..8a53b74 100644 (file)
@@ -73,7 +73,7 @@ static struct spi_board_info simone_spi_devices[] __initdata = {
  * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
  */
 static struct gpiod_lookup_table simone_spi_cs_gpio_table = {
-       .dev_id = "ep93xx-spi.0",
+       .dev_id = "spi0",
        .table = {
                GPIO_LOOKUP("A", 1, "cs", GPIO_ACTIVE_LOW),
                { },
index 582e06e..e0e1b11 100644 (file)
@@ -267,7 +267,7 @@ static struct spi_board_info bk3_spi_board_info[] __initdata = {
  * goes through CPLD
  */
 static struct gpiod_lookup_table bk3_spi_cs_gpio_table = {
-       .dev_id = "ep93xx-spi.0",
+       .dev_id = "spi0",
        .table = {
                GPIO_LOOKUP("F", 3, "cs", GPIO_ACTIVE_LOW),
                { },
@@ -316,7 +316,7 @@ static struct spi_board_info ts72xx_spi_devices[] __initdata = {
 };
 
 static struct gpiod_lookup_table ts72xx_spi_cs_gpio_table = {
-       .dev_id = "ep93xx-spi.0",
+       .dev_id = "spi0",
        .table = {
                /* DIO_17 */
                GPIO_LOOKUP("F", 2, "cs", GPIO_ACTIVE_LOW),
index a88a1d8..cbcba31 100644 (file)
@@ -242,7 +242,7 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
 };
 
 static struct gpiod_lookup_table vision_spi_cs_gpio_table = {
-       .dev_id = "ep93xx-spi.0",
+       .dev_id = "spi0",
        .table = {
                GPIO_LOOKUP_IDX("A", 6, "cs", 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("A", 7, "cs", 1, GPIO_ACTIVE_LOW),
index 81159af..14a6c3e 100644 (file)
@@ -126,6 +126,8 @@ restart:
        orr r11, r11, r13                       @ mask all requested interrupts
        str r11, [r12, #OMAP1510_GPIO_INT_MASK]
 
+       str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts
+
        ands r10, r13, #KEYBRD_CLK_MASK         @ extract keyboard status - set?
        beq hksw                                @ no - try next source
 
@@ -133,7 +135,6 @@ restart:
        @@@@@@@@@@@@@@@@@@@@@@
        @ Keyboard clock FIQ mode interrupt handler
        @ r10 now contains KEYBRD_CLK_MASK, use it
-       str r10, [r12, #OMAP1510_GPIO_INT_STATUS]       @ ack the interrupt
        bic r11, r11, r10                               @ unmask it
        str r11, [r12, #OMAP1510_GPIO_INT_MASK]
 
index 43899fa..0254eb9 100644 (file)
@@ -70,9 +70,7 @@ static irqreturn_t deferred_fiq(int irq, void *dev_id)
                         * interrupts default to since commit 80ac93c27441
                         * requires interrupt already acked and unmasked.
                         */
-                       if (irq_chip->irq_ack)
-                               irq_chip->irq_ack(d);
-                       if (irq_chip->irq_unmask)
+                       if (!WARN_ON_ONCE(!irq_chip->irq_unmask))
                                irq_chip->irq_unmask(d);
                }
                for (; irq_counter[gpio] < fiq_count; irq_counter[gpio]++)
index 21c6d4b..8f20819 100644 (file)
@@ -230,3 +230,5 @@ $(obj)/sleep33xx.o $(obj)/sleep43xx.o: $(obj)/pm-asm-offsets.h
 
 targets += pm-asm-offsets.s
 clean-files += pm-asm-offsets.h
+
+obj-$(CONFIG_OMAP_IOMMU)               += omap-iommu.o
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
new file mode 100644 (file)
index 0000000..f1a6ece
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP IOMMU quirks for various TI SoCs
+ *
+ * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/
+ *      Suman Anna <s-anna@ti.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include "omap_hwmod.h"
+#include "omap_device.h"
+#include "powerdomain.h"
+
+int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
+                                   u8 *pwrst)
+{
+       struct powerdomain *pwrdm;
+       struct omap_device *od;
+       u8 next_pwrst;
+
+       od = to_omap_device(pdev);
+       if (!od)
+               return -ENODEV;
+
+       if (od->hwmods_cnt != 1)
+               return -EINVAL;
+
+       pwrdm = omap_hwmod_get_pwrdm(od->hwmods[0]);
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (request)
+               *pwrst = pwrdm_read_next_pwrst(pwrdm);
+
+       if (*pwrst > PWRDM_POWER_RET)
+               return 0;
+
+       next_pwrst = request ? PWRDM_POWER_ON : *pwrst;
+
+       return pwrdm_set_next_pwrst(pwrdm, next_pwrst);
+}
index f9c02f9..5c38457 100644 (file)
@@ -127,6 +127,9 @@ static int __init omap4_sram_init(void)
        struct device_node *np;
        struct gen_pool *sram_pool;
 
+       if (!soc_is_omap44xx() && !soc_is_omap54xx())
+               return 0;
+
        np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu");
        if (!np)
                pr_warn("%s:Unable to allocate sram needed to handle errata I688\n",
index 4a5b4ae..1ec21e9 100644 (file)
@@ -379,7 +379,8 @@ static struct omap_hwmod dra7xx_dcan2_hwmod = {
 static struct omap_hwmod_class_sysconfig dra7xx_epwmss_sysc = {
        .rev_offs       = 0x0,
        .sysc_offs      = 0x4,
-       .sysc_flags     = SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET,
+       .sysc_flags     = SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                         SYSC_HAS_RESET_STATUS,
        .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type2,
 };
index 0ce56ad..ea2c842 100644 (file)
@@ -46,6 +46,7 @@ static int __init parse_tag_acorn(const struct tag *tag)
        switch (tag->u.acorn.vram_pages) {
        case 512:
                vram_size += PAGE_SIZE * 256;
+               /* Fall through - ??? */
        case 256:
                vram_size += PAGE_SIZE * 256;
        default:
index 658be97..0ab3a86 100644 (file)
@@ -664,10 +664,6 @@ config ARM_LPAE
                !CPU_32v4 && !CPU_32v3
        select PHYS_ADDR_T_64BIT
        select SWIOTLB
-       select ARCH_HAS_DMA_COHERENT_TO_PFN
-       select ARCH_HAS_DMA_MMAP_PGPROT
-       select ARCH_HAS_SYNC_DMA_FOR_DEVICE
-       select ARCH_HAS_SYNC_DMA_FOR_CPU
        help
          Say Y if you have an ARMv7 processor supporting the LPAE page
          table format and you would like to access memory beyond the
index 6774b03..d42557e 100644 (file)
@@ -2405,9 +2405,7 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
 pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
                unsigned long attrs)
 {
-       if (!dev_is_dma_coherent(dev))
-               return __get_dma_pgprot(attrs, prot);
-       return prot;
+       return __get_dma_pgprot(attrs, prot);
 }
 
 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
index 16d373d..b4be3ba 100644 (file)
@@ -175,6 +175,11 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low,
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
+       phys_addr_t addr = __pfn_to_phys(pfn);
+
+       if (__phys_to_pfn(addr) != pfn)
+               return 0;
+
        return memblock_is_map_memory(__pfn_to_phys(pfn));
 }
 EXPORT_SYMBOL(pfn_valid);
@@ -628,7 +633,8 @@ static void update_sections_early(struct section_perm perms[], int n)
                if (t->flags & PF_KTHREAD)
                        continue;
                for_each_thread(t, s)
-                       set_section_perms(perms, n, true, s->mm);
+                       if (s->mm)
+                               set_section_perms(perms, n, true, s->mm);
        }
        set_section_perms(perms, n, true, current->active_mm);
        set_section_perms(perms, n, true, &init_mm);
diff --git a/arch/arm64/Kbuild b/arch/arm64/Kbuild
new file mode 100644 (file)
index 0000000..d646582
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y                  += kernel/ mm/
+obj-$(CONFIG_NET)      += net/
+obj-$(CONFIG_KVM)      += kvm/
+obj-$(CONFIG_XEN)      += xen/
+obj-$(CONFIG_CRYPTO)   += crypto/
index 3adcec0..6ae6ad8 100644 (file)
@@ -148,6 +148,7 @@ config ARM64
        select HAVE_FAST_GUP
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_TRACER
+       select HAVE_FUNCTION_ERROR_INJECTION
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_GCC_PLUGINS
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
@@ -286,7 +287,7 @@ config PGTABLE_LEVELS
        int
        default 2 if ARM64_16K_PAGES && ARM64_VA_BITS_36
        default 2 if ARM64_64K_PAGES && ARM64_VA_BITS_42
-       default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52)
+       default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_VA_BITS_52)
        default 3 if ARM64_4K_PAGES && ARM64_VA_BITS_39
        default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47
        default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48
@@ -297,6 +298,21 @@ config ARCH_SUPPORTS_UPROBES
 config ARCH_PROC_KCORE_TEXT
        def_bool y
 
+config KASAN_SHADOW_OFFSET
+       hex
+       depends on KASAN
+       default 0xdfffa00000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS
+       default 0xdfffd00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS
+       default 0xdffffe8000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
+       default 0xdfffffd000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS
+       default 0xdffffffa00000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS
+       default 0xefff900000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && KASAN_SW_TAGS
+       default 0xefffc80000000000 if ARM64_VA_BITS_47 && KASAN_SW_TAGS
+       default 0xeffffe4000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
+       default 0xefffffc800000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
+       default 0xeffffff900000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
+       default 0xffffffffffffffff
+
 source "arch/arm64/Kconfig.platforms"
 
 menu "Kernel Features"
@@ -744,13 +760,14 @@ config ARM64_VA_BITS_47
 config ARM64_VA_BITS_48
        bool "48-bit"
 
-config ARM64_USER_VA_BITS_52
-       bool "52-bit (user)"
+config ARM64_VA_BITS_52
+       bool "52-bit"
        depends on ARM64_64K_PAGES && (ARM64_PAN || !ARM64_SW_TTBR0_PAN)
        help
          Enable 52-bit virtual addressing for userspace when explicitly
-         requested via a hint to mmap(). The kernel will continue to
-         use 48-bit virtual addresses for its own mappings.
+         requested via a hint to mmap(). The kernel will also use 52-bit
+         virtual addresses for its own mappings (provided HW support for
+         this feature is available, otherwise it reverts to 48-bit).
 
          NOTE: Enabling 52-bit virtual addressing in conjunction with
          ARMv8.3 Pointer Authentication will result in the PAC being
@@ -763,7 +780,7 @@ endchoice
 
 config ARM64_FORCE_52BIT
        bool "Force 52-bit virtual addresses for userspace"
-       depends on ARM64_USER_VA_BITS_52 && EXPERT
+       depends on ARM64_VA_BITS_52 && EXPERT
        help
          For systems with 52-bit userspace VAs enabled, the kernel will attempt
          to maintain compatibility with older software by providing 48-bit VAs
@@ -780,7 +797,8 @@ config ARM64_VA_BITS
        default 39 if ARM64_VA_BITS_39
        default 42 if ARM64_VA_BITS_42
        default 47 if ARM64_VA_BITS_47
-       default 48 if ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52
+       default 48 if ARM64_VA_BITS_48
+       default 52 if ARM64_VA_BITS_52
 
 choice
        prompt "Physical address space size"
@@ -1110,6 +1128,15 @@ config ARM64_SW_TTBR0_PAN
          zeroed area and reserved ASID. The user access routines
          restore the valid TTBR0_EL1 temporarily.
 
+config ARM64_TAGGED_ADDR_ABI
+       bool "Enable the tagged user addresses syscall ABI"
+       default y
+       help
+         When this option is enabled, user applications can opt in to a
+         relaxed ABI via prctl() allowing tagged addresses to be passed
+         to system calls as pointer arguments. For details, see
+         Documentation/arm64/tagged-address-abi.txt.
+
 menuconfig COMPAT
        bool "Kernel support for 32-bit EL0"
        depends on ARM64_4K_PAGES || EXPERT
@@ -1263,6 +1290,7 @@ config ARM64_PAN
 
 config ARM64_LSE_ATOMICS
        bool "Atomic instructions"
+       depends on JUMP_LABEL
        default y
        help
          As part of the Large System Extensions, ARMv8.1 introduces new
@@ -1467,6 +1495,7 @@ endif
 
 config RELOCATABLE
        bool
+       select ARCH_HAS_RELR
        help
          This builds the kernel as a Position Independent Executable (PIE),
          which retains all relocation metadata required to relocate the
index 61de992..f843d29 100644 (file)
@@ -39,6 +39,12 @@ $(warning LSE atomics not supported by binutils)
   endif
 endif
 
+cc_has_k_constraint := $(call try-run,echo                             \
+       'int main(void) {                                               \
+               asm volatile("and w0, w0, %w0" :: "K" (4294967295));    \
+               return 0;                                               \
+       }' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)
+
 ifeq ($(CONFIG_ARM64), y)
 brokengasinst := $(call as-instr,1:\n.inst 0\n.rept . - 1b\n\nnop\n.endr\n,,-DCONFIG_BROKEN_GAS_INST=1)
 
@@ -63,7 +69,8 @@ ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y)
   endif
 endif
 
-KBUILD_CFLAGS  += -mgeneral-regs-only $(lseinstr) $(brokengasinst) $(compat_vdso)
+KBUILD_CFLAGS  += -mgeneral-regs-only $(lseinstr) $(brokengasinst)     \
+                  $(compat_vdso) $(cc_has_k_constraint)
 KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS  += $(call cc-disable-warning, psabi)
 KBUILD_AFLAGS  += $(lseinstr) $(brokengasinst) $(compat_vdso)
@@ -126,21 +133,9 @@ KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
 
-# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
-#                               - (1 << (64 - KASAN_SHADOW_SCALE_SHIFT))
-# in 32-bit arithmetic
-KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
-       (0xffffffff & (-1 << ($(CONFIG_ARM64_VA_BITS) - 32))) \
-       + (1 << ($(CONFIG_ARM64_VA_BITS) - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) \
-       - (1 << (64 - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) )) )
-
 export TEXT_OFFSET GZFLAGS
 
-core-y         += arch/arm64/kernel/ arch/arm64/mm/
-core-$(CONFIG_NET) += arch/arm64/net/
-core-$(CONFIG_KVM) += arch/arm64/kvm/
-core-$(CONFIG_XEN) += arch/arm64/xen/
-core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
+core-y         += arch/arm64/
 libs-y         := arch/arm64/lib/ $(libs-y)
 core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 
index c7a8736..12aa7ea 100644 (file)
        pinctrl-names = "default";
 };
 
+&ir {
+       status = "okay";
+       pinctrl-0 = <&remote_input_ao_pins>;
+       pinctrl-names = "default";
+};
+
 &pwm_ef {
        status = "okay";
        pinctrl-0 = <&pwm_e_pins>;
index f8d43e3..1785552 100644 (file)
                                clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
                                clock-names = "ddr";
                                phys = <&usb2_phy1>;
+                               phy-names = "usb2-phy";
                                dr_mode = "peripheral";
                                g-rx-fifo-size = <192>;
                                g-np-tx-fifo-size = <128>;
index 81780ff..4e916e1 100644 (file)
@@ -53,6 +53,7 @@
 
                gpio = <&gpio_ao GPIOAO_8 GPIO_ACTIVE_HIGH>;
                enable-active-high;
+               regulator-always-on;
        };
 
        tf_io: gpio-regulator-tf_io {
index 3311a98..23fd022 100644 (file)
        mmc-hs200-1_8v;
        non-removable;
        fixed-emmc-driver-type = <1>;
+       status = "okay";
 };
 
 &usb_extal_clk {
index 0711170..3aa2564 100644 (file)
@@ -97,7 +97,7 @@
                reg = <0x0 0x48000000 0x0 0x18000000>;
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       reg_12p0v: regulator1 {
+       reg_12p0v: regulator-12p0v {
                compatible = "regulator-fixed";
                regulator-name = "D12.0V";
                regulator-min-microvolt = <12000000>;
index e3a15c7..b8cf7c8 100644 (file)
@@ -123,17 +123,6 @@ alternative_else
 alternative_endif
        .endm
 
-/*
- * Sanitise a 64-bit bounded index wrt speculation, returning zero if out
- * of bounds.
- */
-       .macro  mask_nospec64, idx, limit, tmp
-       sub     \tmp, \idx, \limit
-       bic     \tmp, \tmp, \idx
-       and     \idx, \idx, \tmp, asr #63
-       csdb
-       .endm
-
 /*
  * NOP sequence
  */
@@ -349,6 +338,13 @@ alternative_endif
        bfi     \valreg, \t0sz, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
        .endm
 
+/*
+ * tcr_set_t1sz - update TCR.T1SZ
+ */
+       .macro  tcr_set_t1sz, valreg, t1sz
+       bfi     \valreg, \t1sz, #TCR_T1SZ_OFFSET, #TCR_TxSZ_WIDTH
+       .endm
+
 /*
  * tcr_compute_pa_size - set TCR.(I)PS to the highest supported
  * ID_AA64MMFR0_EL1.PARange value
@@ -538,9 +534,13 @@ USER(\label, ic    ivau, \tmp2)                    // invalidate I line PoU
  * In future this may be nop'ed out when dealing with 52-bit kernel VAs.
  *     ttbr: Value of ttbr to set, modified.
  */
-       .macro  offset_ttbr1, ttbr
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+       .macro  offset_ttbr1, ttbr, tmp
+#ifdef CONFIG_ARM64_VA_BITS_52
+       mrs_s   \tmp, SYS_ID_AA64MMFR2_EL1
+       and     \tmp, \tmp, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
+       cbnz    \tmp, .Lskipoffs_\@
        orr     \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
+.Lskipoffs_\@ :
 #endif
        .endm
 
@@ -550,7 +550,7 @@ USER(\label, ic     ivau, \tmp2)                    // invalidate I line PoU
  * to be nop'ed out when dealing with 52-bit kernel VAs.
  */
        .macro  restore_ttbr1, ttbr
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+#ifdef CONFIG_ARM64_VA_BITS_52
        bic     \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
 #endif
        .endm
index 657b045..9543b5e 100644 (file)
 #include <linux/types.h>
 
 #include <asm/barrier.h>
+#include <asm/cmpxchg.h>
 #include <asm/lse.h>
 
-#ifdef __KERNEL__
-
-#define __ARM64_IN_ATOMIC_IMPL
-
-#if defined(CONFIG_ARM64_LSE_ATOMICS) && defined(CONFIG_AS_LSE)
-#include <asm/atomic_lse.h>
-#else
-#include <asm/atomic_ll_sc.h>
-#endif
-
-#undef __ARM64_IN_ATOMIC_IMPL
-
-#include <asm/cmpxchg.h>
+#define ATOMIC_OP(op)                                                  \
+static inline void arch_##op(int i, atomic_t *v)                       \
+{                                                                      \
+       __lse_ll_sc_body(op, i, v);                                     \
+}
+
+ATOMIC_OP(atomic_andnot)
+ATOMIC_OP(atomic_or)
+ATOMIC_OP(atomic_xor)
+ATOMIC_OP(atomic_add)
+ATOMIC_OP(atomic_and)
+ATOMIC_OP(atomic_sub)
+
+#undef ATOMIC_OP
+
+#define ATOMIC_FETCH_OP(name, op)                                      \
+static inline int arch_##op##name(int i, atomic_t *v)                  \
+{                                                                      \
+       return __lse_ll_sc_body(op##name, i, v);                        \
+}
+
+#define ATOMIC_FETCH_OPS(op)                                           \
+       ATOMIC_FETCH_OP(_relaxed, op)                                   \
+       ATOMIC_FETCH_OP(_acquire, op)                                   \
+       ATOMIC_FETCH_OP(_release, op)                                   \
+       ATOMIC_FETCH_OP(        , op)
+
+ATOMIC_FETCH_OPS(atomic_fetch_andnot)
+ATOMIC_FETCH_OPS(atomic_fetch_or)
+ATOMIC_FETCH_OPS(atomic_fetch_xor)
+ATOMIC_FETCH_OPS(atomic_fetch_add)
+ATOMIC_FETCH_OPS(atomic_fetch_and)
+ATOMIC_FETCH_OPS(atomic_fetch_sub)
+ATOMIC_FETCH_OPS(atomic_add_return)
+ATOMIC_FETCH_OPS(atomic_sub_return)
+
+#undef ATOMIC_FETCH_OP
+#undef ATOMIC_FETCH_OPS
+
+#define ATOMIC64_OP(op)                                                        \
+static inline void arch_##op(long i, atomic64_t *v)                    \
+{                                                                      \
+       __lse_ll_sc_body(op, i, v);                                     \
+}
+
+ATOMIC64_OP(atomic64_andnot)
+ATOMIC64_OP(atomic64_or)
+ATOMIC64_OP(atomic64_xor)
+ATOMIC64_OP(atomic64_add)
+ATOMIC64_OP(atomic64_and)
+ATOMIC64_OP(atomic64_sub)
+
+#undef ATOMIC64_OP
+
+#define ATOMIC64_FETCH_OP(name, op)                                    \
+static inline long arch_##op##name(long i, atomic64_t *v)              \
+{                                                                      \
+       return __lse_ll_sc_body(op##name, i, v);                        \
+}
+
+#define ATOMIC64_FETCH_OPS(op)                                         \
+       ATOMIC64_FETCH_OP(_relaxed, op)                                 \
+       ATOMIC64_FETCH_OP(_acquire, op)                                 \
+       ATOMIC64_FETCH_OP(_release, op)                                 \
+       ATOMIC64_FETCH_OP(        , op)
+
+ATOMIC64_FETCH_OPS(atomic64_fetch_andnot)
+ATOMIC64_FETCH_OPS(atomic64_fetch_or)
+ATOMIC64_FETCH_OPS(atomic64_fetch_xor)
+ATOMIC64_FETCH_OPS(atomic64_fetch_add)
+ATOMIC64_FETCH_OPS(atomic64_fetch_and)
+ATOMIC64_FETCH_OPS(atomic64_fetch_sub)
+ATOMIC64_FETCH_OPS(atomic64_add_return)
+ATOMIC64_FETCH_OPS(atomic64_sub_return)
+
+#undef ATOMIC64_FETCH_OP
+#undef ATOMIC64_FETCH_OPS
+
+static inline long arch_atomic64_dec_if_positive(atomic64_t *v)
+{
+       return __lse_ll_sc_body(atomic64_dec_if_positive, v);
+}
 
 #define ATOMIC_INIT(i) { (i) }
 
 
 #include <asm-generic/atomic-instrumented.h>
 
-#endif
-#endif
+#endif /* __ASM_ATOMIC_H */
index c8c850b..7b01214 100644 (file)
 #ifndef __ASM_ATOMIC_LL_SC_H
 #define __ASM_ATOMIC_LL_SC_H
 
-#ifndef __ARM64_IN_ATOMIC_IMPL
-#error "please don't include this file directly"
+#include <linux/stringify.h>
+
+#if IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS) && IS_ENABLED(CONFIG_AS_LSE)
+#define __LL_SC_FALLBACK(asm_ops)                                      \
+"      b       3f\n"                                                   \
+"      .subsection     1\n"                                            \
+"3:\n"                                                                 \
+asm_ops "\n"                                                           \
+"      b       4f\n"                                                   \
+"      .previous\n"                                                    \
+"4:\n"
+#else
+#define __LL_SC_FALLBACK(asm_ops) asm_ops
+#endif
+
+#ifndef CONFIG_CC_HAS_K_CONSTRAINT
+#define K
 #endif
 
 /*
  * AArch64 UP and SMP safe atomic ops.  We use load exclusive and
  * store exclusive to ensure that these are atomic.  We may loop
  * to ensure that the update happens.
- *
- * NOTE: these functions do *not* follow the PCS and must explicitly
- * save any clobbered registers other than x0 (regardless of return
- * value).  This is achieved through -fcall-saved-* compiler flags for
- * this file, which unfortunately don't work on a per-function basis
- * (the optimize attribute silently ignores these options).
  */
 
-#define ATOMIC_OP(op, asm_op)                                          \
-__LL_SC_INLINE void                                                    \
-__LL_SC_PREFIX(arch_atomic_##op(int i, atomic_t *v))                   \
+#define ATOMIC_OP(op, asm_op, constraint)                              \
+static inline void                                                     \
+__ll_sc_atomic_##op(int i, atomic_t *v)                                        \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
                                                                        \
        asm volatile("// atomic_" #op "\n"                              \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %2\n"                                        \
 "1:    ldxr    %w0, %2\n"                                              \
 "      " #asm_op "     %w0, %w0, %w3\n"                                \
 "      stxr    %w1, %w0, %2\n"                                         \
-"      cbnz    %w1, 1b"                                                \
+"      cbnz    %w1, 1b\n")                                             \
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
-       : "Ir" (i));                                                    \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic_##op);
+       : __stringify(constraint) "r" (i));                             \
+}
 
-#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op)           \
-__LL_SC_INLINE int                                                     \
-__LL_SC_PREFIX(arch_atomic_##op##_return##name(int i, atomic_t *v))    \
+#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\
+static inline int                                                      \
+__ll_sc_atomic_##op##_return##name(int i, atomic_t *v)                 \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
                                                                        \
        asm volatile("// atomic_" #op "_return" #name "\n"              \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %2\n"                                        \
 "1:    ld" #acq "xr    %w0, %2\n"                                      \
 "      " #asm_op "     %w0, %w0, %w3\n"                                \
 "      st" #rel "xr    %w1, %w0, %2\n"                                 \
 "      cbnz    %w1, 1b\n"                                              \
-"      " #mb                                                           \
+"      " #mb )                                                         \
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
-       : "Ir" (i)                                                      \
+       : __stringify(constraint) "r" (i)                               \
        : cl);                                                          \
                                                                        \
        return result;                                                  \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic_##op##_return##name);
+}
 
-#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op)            \
-__LL_SC_INLINE int                                                     \
-__LL_SC_PREFIX(arch_atomic_fetch_##op##name(int i, atomic_t *v))       \
+#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint) \
+static inline int                                                      \
+__ll_sc_atomic_fetch_##op##name(int i, atomic_t *v)                    \
 {                                                                      \
        unsigned long tmp;                                              \
        int val, result;                                                \
                                                                        \
        asm volatile("// atomic_fetch_" #op #name "\n"                  \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %3\n"                                        \
 "1:    ld" #acq "xr    %w0, %3\n"                                      \
 "      " #asm_op "     %w1, %w0, %w4\n"                                \
 "      st" #rel "xr    %w2, %w1, %3\n"                                 \
 "      cbnz    %w2, 1b\n"                                              \
-"      " #mb                                                           \
+"      " #mb )                                                         \
        : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter)   \
-       : "Ir" (i)                                                      \
+       : __stringify(constraint) "r" (i)                               \
        : cl);                                                          \
                                                                        \
        return result;                                                  \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic_fetch_##op##name);
+}
 
 #define ATOMIC_OPS(...)                                                        \
        ATOMIC_OP(__VA_ARGS__)                                          \
@@ -99,8 +108,8 @@ __LL_SC_EXPORT(arch_atomic_fetch_##op##name);
        ATOMIC_FETCH_OP (_acquire,        , a,  , "memory", __VA_ARGS__)\
        ATOMIC_FETCH_OP (_release,        ,  , l, "memory", __VA_ARGS__)
 
-ATOMIC_OPS(add, add)
-ATOMIC_OPS(sub, sub)
+ATOMIC_OPS(add, add, I)
+ATOMIC_OPS(sub, sub, J)
 
 #undef ATOMIC_OPS
 #define ATOMIC_OPS(...)                                                        \
@@ -110,77 +119,82 @@ ATOMIC_OPS(sub, sub)
        ATOMIC_FETCH_OP (_acquire,        , a,  , "memory", __VA_ARGS__)\
        ATOMIC_FETCH_OP (_release,        ,  , l, "memory", __VA_ARGS__)
 
-ATOMIC_OPS(and, and)
-ATOMIC_OPS(andnot, bic)
-ATOMIC_OPS(or, orr)
-ATOMIC_OPS(xor, eor)
+ATOMIC_OPS(and, and, K)
+ATOMIC_OPS(or, orr, K)
+ATOMIC_OPS(xor, eor, K)
+/*
+ * GAS converts the mysterious and undocumented BIC (immediate) alias to
+ * an AND (immediate) instruction with the immediate inverted. We don't
+ * have a constraint for this, so fall back to register.
+ */
+ATOMIC_OPS(andnot, bic, )
 
 #undef ATOMIC_OPS
 #undef ATOMIC_FETCH_OP
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define ATOMIC64_OP(op, asm_op)                                                \
-__LL_SC_INLINE void                                                    \
-__LL_SC_PREFIX(arch_atomic64_##op(s64 i, atomic64_t *v))               \
+#define ATOMIC64_OP(op, asm_op, constraint)                            \
+static inline void                                                     \
+__ll_sc_atomic64_##op(s64 i, atomic64_t *v)                            \
 {                                                                      \
        s64 result;                                                     \
        unsigned long tmp;                                              \
                                                                        \
        asm volatile("// atomic64_" #op "\n"                            \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %2\n"                                        \
 "1:    ldxr    %0, %2\n"                                               \
 "      " #asm_op "     %0, %0, %3\n"                                   \
 "      stxr    %w1, %0, %2\n"                                          \
-"      cbnz    %w1, 1b"                                                \
+"      cbnz    %w1, 1b")                                               \
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
-       : "Ir" (i));                                                    \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic64_##op);
+       : __stringify(constraint) "r" (i));                             \
+}
 
-#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op)         \
-__LL_SC_INLINE s64                                                     \
-__LL_SC_PREFIX(arch_atomic64_##op##_return##name(s64 i, atomic64_t *v))\
+#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\
+static inline long                                                     \
+__ll_sc_atomic64_##op##_return##name(s64 i, atomic64_t *v)             \
 {                                                                      \
        s64 result;                                                     \
        unsigned long tmp;                                              \
                                                                        \
        asm volatile("// atomic64_" #op "_return" #name "\n"            \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %2\n"                                        \
 "1:    ld" #acq "xr    %0, %2\n"                                       \
 "      " #asm_op "     %0, %0, %3\n"                                   \
 "      st" #rel "xr    %w1, %0, %2\n"                                  \
 "      cbnz    %w1, 1b\n"                                              \
-"      " #mb                                                           \
+"      " #mb )                                                         \
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)                \
-       : "Ir" (i)                                                      \
+       : __stringify(constraint) "r" (i)                               \
        : cl);                                                          \
                                                                        \
        return result;                                                  \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic64_##op##_return##name);
+}
 
-#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op)          \
-__LL_SC_INLINE s64                                                     \
-__LL_SC_PREFIX(arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v))   \
+#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint)\
+static inline long                                                     \
+__ll_sc_atomic64_fetch_##op##name(s64 i, atomic64_t *v)                \
 {                                                                      \
        s64 result, val;                                                \
        unsigned long tmp;                                              \
                                                                        \
        asm volatile("// atomic64_fetch_" #op #name "\n"                \
+       __LL_SC_FALLBACK(                                               \
 "      prfm    pstl1strm, %3\n"                                        \
 "1:    ld" #acq "xr    %0, %3\n"                                       \
 "      " #asm_op "     %1, %0, %4\n"                                   \
 "      st" #rel "xr    %w2, %1, %3\n"                                  \
 "      cbnz    %w2, 1b\n"                                              \
-"      " #mb                                                           \
+"      " #mb )                                                         \
        : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter)   \
-       : "Ir" (i)                                                      \
+       : __stringify(constraint) "r" (i)                               \
        : cl);                                                          \
                                                                        \
        return result;                                                  \
-}                                                                      \
-__LL_SC_EXPORT(arch_atomic64_fetch_##op##name);
+}
 
 #define ATOMIC64_OPS(...)                                              \
        ATOMIC64_OP(__VA_ARGS__)                                        \
@@ -193,8 +207,8 @@ __LL_SC_EXPORT(arch_atomic64_fetch_##op##name);
        ATOMIC64_FETCH_OP (_acquire,, a,  , "memory", __VA_ARGS__)      \
        ATOMIC64_FETCH_OP (_release,,  , l, "memory", __VA_ARGS__)
 
-ATOMIC64_OPS(add, add)
-ATOMIC64_OPS(sub, sub)
+ATOMIC64_OPS(add, add, I)
+ATOMIC64_OPS(sub, sub, J)
 
 #undef ATOMIC64_OPS
 #define ATOMIC64_OPS(...)                                              \
@@ -204,23 +218,29 @@ ATOMIC64_OPS(sub, sub)
        ATOMIC64_FETCH_OP (_acquire,, a,  , "memory", __VA_ARGS__)      \
        ATOMIC64_FETCH_OP (_release,,  , l, "memory", __VA_ARGS__)
 
-ATOMIC64_OPS(and, and)
-ATOMIC64_OPS(andnot, bic)
-ATOMIC64_OPS(or, orr)
-ATOMIC64_OPS(xor, eor)
+ATOMIC64_OPS(and, and, L)
+ATOMIC64_OPS(or, orr, L)
+ATOMIC64_OPS(xor, eor, L)
+/*
+ * GAS converts the mysterious and undocumented BIC (immediate) alias to
+ * an AND (immediate) instruction with the immediate inverted. We don't
+ * have a constraint for this, so fall back to register.
+ */
+ATOMIC64_OPS(andnot, bic, )
 
 #undef ATOMIC64_OPS
 #undef ATOMIC64_FETCH_OP
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
-__LL_SC_INLINE s64
-__LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v))
+static inline s64
+__ll_sc_atomic64_dec_if_positive(atomic64_t *v)
 {
        s64 result;
        unsigned long tmp;
 
        asm volatile("// atomic64_dec_if_positive\n"
+       __LL_SC_FALLBACK(
 "      prfm    pstl1strm, %2\n"
 "1:    ldxr    %0, %2\n"
 "      subs    %0, %0, #1\n"
@@ -228,20 +248,19 @@ __LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v))
 "      stlxr   %w1, %0, %2\n"
 "      cbnz    %w1, 1b\n"
 "      dmb     ish\n"
-"2:"
+"2:")
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
        :
        : "cc", "memory");
 
        return result;
 }
-__LL_SC_EXPORT(arch_atomic64_dec_if_positive);
 
-#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl)             \
-__LL_SC_INLINE u##sz                                                   \
-__LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr,           \
+#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl, constraint) \
+static inline u##sz                                                    \
+__ll_sc__cmpxchg_case_##name##sz(volatile void *ptr,                   \
                                         unsigned long old,             \
-                                        u##sz new))                    \
+                                        u##sz new)                     \
 {                                                                      \
        unsigned long tmp;                                              \
        u##sz oldval;                                                   \
@@ -255,6 +274,7 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr,                \
                old = (u##sz)old;                                       \
                                                                        \
        asm volatile(                                                   \
+       __LL_SC_FALLBACK(                                               \
        "       prfm    pstl1strm, %[v]\n"                              \
        "1:     ld" #acq "xr" #sfx "\t%" #w "[oldval], %[v]\n"          \
        "       eor     %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n"  \
@@ -262,46 +282,51 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr,              \
        "       st" #rel "xr" #sfx "\t%w[tmp], %" #w "[new], %[v]\n"    \
        "       cbnz    %w[tmp], 1b\n"                                  \
        "       " #mb "\n"                                              \
-       "2:"                                                            \
+       "2:")                                                           \
        : [tmp] "=&r" (tmp), [oldval] "=&r" (oldval),                   \
          [v] "+Q" (*(u##sz *)ptr)                                      \
-       : [old] "Kr" (old), [new] "r" (new)                             \
+       : [old] __stringify(constraint) "r" (old), [new] "r" (new)      \
        : cl);                                                          \
                                                                        \
        return oldval;                                                  \
-}                                                                      \
-__LL_SC_EXPORT(__cmpxchg_case_##name##sz);
+}
 
-__CMPXCHG_CASE(w, b,     ,  8,        ,  ,  ,         )
-__CMPXCHG_CASE(w, h,     , 16,        ,  ,  ,         )
-__CMPXCHG_CASE(w,  ,     , 32,        ,  ,  ,         )
-__CMPXCHG_CASE( ,  ,     , 64,        ,  ,  ,         )
-__CMPXCHG_CASE(w, b, acq_,  8,        , a,  , "memory")
-__CMPXCHG_CASE(w, h, acq_, 16,        , a,  , "memory")
-__CMPXCHG_CASE(w,  , acq_, 32,        , a,  , "memory")
-__CMPXCHG_CASE( ,  , acq_, 64,        , a,  , "memory")
-__CMPXCHG_CASE(w, b, rel_,  8,        ,  , l, "memory")
-__CMPXCHG_CASE(w, h, rel_, 16,        ,  , l, "memory")
-__CMPXCHG_CASE(w,  , rel_, 32,        ,  , l, "memory")
-__CMPXCHG_CASE( ,  , rel_, 64,        ,  , l, "memory")
-__CMPXCHG_CASE(w, b,  mb_,  8, dmb ish,  , l, "memory")
-__CMPXCHG_CASE(w, h,  mb_, 16, dmb ish,  , l, "memory")
-__CMPXCHG_CASE(w,  ,  mb_, 32, dmb ish,  , l, "memory")
-__CMPXCHG_CASE( ,  ,  mb_, 64, dmb ish,  , l, "memory")
+/*
+ * Earlier versions of GCC (no later than 8.1.0) appear to incorrectly
+ * handle the 'K' constraint for the value 4294967295 - thus we use no
+ * constraint for 32 bit operations.
+ */
+__CMPXCHG_CASE(w, b,     ,  8,        ,  ,  ,         , K)
+__CMPXCHG_CASE(w, h,     , 16,        ,  ,  ,         , K)
+__CMPXCHG_CASE(w,  ,     , 32,        ,  ,  ,         , K)
+__CMPXCHG_CASE( ,  ,     , 64,        ,  ,  ,         , L)
+__CMPXCHG_CASE(w, b, acq_,  8,        , a,  , "memory", K)
+__CMPXCHG_CASE(w, h, acq_, 16,        , a,  , "memory", K)
+__CMPXCHG_CASE(w,  , acq_, 32,        , a,  , "memory", K)
+__CMPXCHG_CASE( ,  , acq_, 64,        , a,  , "memory", L)
+__CMPXCHG_CASE(w, b, rel_,  8,        ,  , l, "memory", K)
+__CMPXCHG_CASE(w, h, rel_, 16,        ,  , l, "memory", K)
+__CMPXCHG_CASE(w,  , rel_, 32,        ,  , l, "memory", K)
+__CMPXCHG_CASE( ,  , rel_, 64,        ,  , l, "memory", L)
+__CMPXCHG_CASE(w, b,  mb_,  8, dmb ish,  , l, "memory", K)
+__CMPXCHG_CASE(w, h,  mb_, 16, dmb ish,  , l, "memory", K)
+__CMPXCHG_CASE(w,  ,  mb_, 32, dmb ish,  , l, "memory", K)
+__CMPXCHG_CASE( ,  ,  mb_, 64, dmb ish,  , l, "memory", L)
 
 #undef __CMPXCHG_CASE
 
 #define __CMPXCHG_DBL(name, mb, rel, cl)                               \
-__LL_SC_INLINE long                                                    \
-__LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1,              \
+static inline long                                                     \
+__ll_sc__cmpxchg_double##name(unsigned long old1,                      \
                                      unsigned long old2,               \
                                      unsigned long new1,               \
                                      unsigned long new2,               \
-                                     volatile void *ptr))              \
+                                     volatile void *ptr)               \
 {                                                                      \
        unsigned long tmp, ret;                                         \
                                                                        \
        asm volatile("// __cmpxchg_double" #name "\n"                   \
+       __LL_SC_FALLBACK(                                               \
        "       prfm    pstl1strm, %2\n"                                \
        "1:     ldxp    %0, %1, %2\n"                                   \
        "       eor     %0, %0, %3\n"                                   \
@@ -311,18 +336,18 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1,         \
        "       st" #rel "xp    %w0, %5, %6, %2\n"                      \
        "       cbnz    %w0, 1b\n"                                      \
        "       " #mb "\n"                                              \
-       "2:"                                                            \
+       "2:")                                                           \
        : "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr)        \
        : "r" (old1), "r" (old2), "r" (new1), "r" (new2)                \
        : cl);                                                          \
                                                                        \
        return ret;                                                     \
-}                                                                      \
-__LL_SC_EXPORT(__cmpxchg_double##name);
+}
 
 __CMPXCHG_DBL(   ,        ,  ,         )
 __CMPXCHG_DBL(_mb, dmb ish, l, "memory")
 
 #undef __CMPXCHG_DBL
+#undef K
 
 #endif /* __ASM_ATOMIC_LL_SC_H */
index 69acb1c..c6bd87d 100644 (file)
 #ifndef __ASM_ATOMIC_LSE_H
 #define __ASM_ATOMIC_LSE_H
 
-#ifndef __ARM64_IN_ATOMIC_IMPL
-#error "please don't include this file directly"
-#endif
-
-#define __LL_SC_ATOMIC(op)     __LL_SC_CALL(arch_atomic_##op)
 #define ATOMIC_OP(op, asm_op)                                          \
-static inline void arch_atomic_##op(int i, atomic_t *v)                        \
+static inline void __lse_atomic_##op(int i, atomic_t *v)                       \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(op),          \
-"      " #asm_op "     %w[i], %[v]\n")                                 \
-       : [i] "+r" (w0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS);                                            \
+       asm volatile(                                                   \
+"      " #asm_op "     %w[i], %[v]\n"                                  \
+       : [i] "+r" (i), [v] "+Q" (v->counter)                           \
+       : "r" (v));                                                     \
 }
 
 ATOMIC_OP(andnot, stclr)
@@ -36,21 +27,15 @@ ATOMIC_OP(add, stadd)
 #undef ATOMIC_OP
 
 #define ATOMIC_FETCH_OP(name, mb, op, asm_op, cl...)                   \
-static inline int arch_atomic_fetch_##op##name(int i, atomic_t *v)     \
+static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v)    \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC(fetch_##op##name),                               \
-       /* LSE atomics */                                               \
-"      " #asm_op #mb " %w[i], %w[i], %[v]")                            \
-       : [i] "+r" (w0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       asm volatile(                                                   \
+"      " #asm_op #mb " %w[i], %w[i], %[v]"                             \
+       : [i] "+r" (i), [v] "+Q" (v->counter)                           \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return w0;                                                      \
+       return i;                                                       \
 }
 
 #define ATOMIC_FETCH_OPS(op, asm_op)                                   \
@@ -68,23 +53,18 @@ ATOMIC_FETCH_OPS(add, ldadd)
 #undef ATOMIC_FETCH_OPS
 
 #define ATOMIC_OP_ADD_RETURN(name, mb, cl...)                          \
-static inline int arch_atomic_add_return##name(int i, atomic_t *v)     \
+static inline int __lse_atomic_add_return##name(int i, atomic_t *v)    \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
+       u32 tmp;                                                        \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC(add_return##name)                                \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
-       "       ldadd" #mb "    %w[i], w30, %[v]\n"                     \
-       "       add     %w[i], %w[i], w30")                             \
-       : [i] "+r" (w0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       asm volatile(                                                   \
+       "       ldadd" #mb "    %w[i], %w[tmp], %[v]\n"                 \
+       "       add     %w[i], %w[i], %w[tmp]"                          \
+       : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)        \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return w0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC_OP_ADD_RETURN(_relaxed,   )
@@ -94,41 +74,26 @@ ATOMIC_OP_ADD_RETURN(        , al, "memory")
 
 #undef ATOMIC_OP_ADD_RETURN
 
-static inline void arch_atomic_and(int i, atomic_t *v)
+static inline void __lse_atomic_and(int i, atomic_t *v)
 {
-       register int w0 asm ("w0") = i;
-       register atomic_t *x1 asm ("x1") = v;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       __LL_SC_ATOMIC(and)
-       __nops(1),
-       /* LSE atomics */
+       asm volatile(
        "       mvn     %w[i], %w[i]\n"
-       "       stclr   %w[i], %[v]")
-       : [i] "+&r" (w0), [v] "+Q" (v->counter)
-       : "r" (x1)
-       : __LL_SC_CLOBBERS);
+       "       stclr   %w[i], %[v]"
+       : [i] "+&r" (i), [v] "+Q" (v->counter)
+       : "r" (v));
 }
 
 #define ATOMIC_FETCH_OP_AND(name, mb, cl...)                           \
-static inline int arch_atomic_fetch_and##name(int i, atomic_t *v)      \
+static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v)     \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC(fetch_and##name)                                 \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       mvn     %w[i], %w[i]\n"                                 \
-       "       ldclr" #mb "    %w[i], %w[i], %[v]")                    \
-       : [i] "+&r" (w0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       "       ldclr" #mb "    %w[i], %w[i], %[v]"                     \
+       : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return w0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC_FETCH_OP_AND(_relaxed,   )
@@ -138,42 +103,29 @@ ATOMIC_FETCH_OP_AND(        , al, "memory")
 
 #undef ATOMIC_FETCH_OP_AND
 
-static inline void arch_atomic_sub(int i, atomic_t *v)
+static inline void __lse_atomic_sub(int i, atomic_t *v)
 {
-       register int w0 asm ("w0") = i;
-       register atomic_t *x1 asm ("x1") = v;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       __LL_SC_ATOMIC(sub)
-       __nops(1),
-       /* LSE atomics */
+       asm volatile(
        "       neg     %w[i], %w[i]\n"
-       "       stadd   %w[i], %[v]")
-       : [i] "+&r" (w0), [v] "+Q" (v->counter)
-       : "r" (x1)
-       : __LL_SC_CLOBBERS);
+       "       stadd   %w[i], %[v]"
+       : [i] "+&r" (i), [v] "+Q" (v->counter)
+       : "r" (v));
 }
 
 #define ATOMIC_OP_SUB_RETURN(name, mb, cl...)                          \
-static inline int arch_atomic_sub_return##name(int i, atomic_t *v)     \
+static inline int __lse_atomic_sub_return##name(int i, atomic_t *v)    \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
+       u32 tmp;                                                        \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC(sub_return##name)                                \
-       __nops(2),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       neg     %w[i], %w[i]\n"                                 \
-       "       ldadd" #mb "    %w[i], w30, %[v]\n"                     \
-       "       add     %w[i], %w[i], w30")                             \
-       : [i] "+&r" (w0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS , ##cl);                                     \
+       "       ldadd" #mb "    %w[i], %w[tmp], %[v]\n"                 \
+       "       add     %w[i], %w[i], %w[tmp]"                          \
+       : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)       \
+       : "r" (v)                                                       \
+       : cl);                                                  \
                                                                        \
-       return w0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC_OP_SUB_RETURN(_relaxed,   )
@@ -184,23 +136,16 @@ ATOMIC_OP_SUB_RETURN(        , al, "memory")
 #undef ATOMIC_OP_SUB_RETURN
 
 #define ATOMIC_FETCH_OP_SUB(name, mb, cl...)                           \
-static inline int arch_atomic_fetch_sub##name(int i, atomic_t *v)      \
+static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v)     \
 {                                                                      \
-       register int w0 asm ("w0") = i;                                 \
-       register atomic_t *x1 asm ("x1") = v;                           \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC(fetch_sub##name)                                 \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       neg     %w[i], %w[i]\n"                                 \
-       "       ldadd" #mb "    %w[i], %w[i], %[v]")                    \
-       : [i] "+&r" (w0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       "       ldadd" #mb "    %w[i], %w[i], %[v]"                     \
+       : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return w0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC_FETCH_OP_SUB(_relaxed,   )
@@ -209,20 +154,14 @@ ATOMIC_FETCH_OP_SUB(_release,  l, "memory")
 ATOMIC_FETCH_OP_SUB(        , al, "memory")
 
 #undef ATOMIC_FETCH_OP_SUB
-#undef __LL_SC_ATOMIC
 
-#define __LL_SC_ATOMIC64(op)   __LL_SC_CALL(arch_atomic64_##op)
 #define ATOMIC64_OP(op, asm_op)                                                \
-static inline void arch_atomic64_##op(s64 i, atomic64_t *v)            \
+static inline void __lse_atomic64_##op(s64 i, atomic64_t *v)           \
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(op),        \
-"      " #asm_op "     %[i], %[v]\n")                                  \
-       : [i] "+r" (x0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS);                                            \
+       asm volatile(                                                   \
+"      " #asm_op "     %[i], %[v]\n"                                   \
+       : [i] "+r" (i), [v] "+Q" (v->counter)                           \
+       : "r" (v));                                                     \
 }
 
 ATOMIC64_OP(andnot, stclr)
@@ -233,21 +172,15 @@ ATOMIC64_OP(add, stadd)
 #undef ATOMIC64_OP
 
 #define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...)                 \
-static inline s64 arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \
+static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC64(fetch_##op##name),                             \
-       /* LSE atomics */                                               \
-"      " #asm_op #mb " %[i], %[i], %[v]")                              \
-       : [i] "+r" (x0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       asm volatile(                                                   \
+"      " #asm_op #mb " %[i], %[i], %[v]"                               \
+       : [i] "+r" (i), [v] "+Q" (v->counter)                           \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return x0;                                                      \
+       return i;                                                       \
 }
 
 #define ATOMIC64_FETCH_OPS(op, asm_op)                                 \
@@ -265,23 +198,18 @@ ATOMIC64_FETCH_OPS(add, ldadd)
 #undef ATOMIC64_FETCH_OPS
 
 #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...)                                \
-static inline s64 arch_atomic64_add_return##name(s64 i, atomic64_t *v) \
+static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
+       unsigned long tmp;                                              \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC64(add_return##name)                              \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
-       "       ldadd" #mb "    %[i], x30, %[v]\n"                      \
-       "       add     %[i], %[i], x30")                               \
-       : [i] "+r" (x0), [v] "+Q" (v->counter)                          \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       asm volatile(                                                   \
+       "       ldadd" #mb "    %[i], %x[tmp], %[v]\n"                  \
+       "       add     %[i], %[i], %x[tmp]"                            \
+       : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)        \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return x0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC64_OP_ADD_RETURN(_relaxed,   )
@@ -291,41 +219,26 @@ ATOMIC64_OP_ADD_RETURN(        , al, "memory")
 
 #undef ATOMIC64_OP_ADD_RETURN
 
-static inline void arch_atomic64_and(s64 i, atomic64_t *v)
+static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
 {
-       register s64 x0 asm ("x0") = i;
-       register atomic64_t *x1 asm ("x1") = v;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       __LL_SC_ATOMIC64(and)
-       __nops(1),
-       /* LSE atomics */
+       asm volatile(
        "       mvn     %[i], %[i]\n"
-       "       stclr   %[i], %[v]")
-       : [i] "+&r" (x0), [v] "+Q" (v->counter)
-       : "r" (x1)
-       : __LL_SC_CLOBBERS);
+       "       stclr   %[i], %[v]"
+       : [i] "+&r" (i), [v] "+Q" (v->counter)
+       : "r" (v));
 }
 
 #define ATOMIC64_FETCH_OP_AND(name, mb, cl...)                         \
-static inline s64 arch_atomic64_fetch_and##name(s64 i, atomic64_t *v)  \
+static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v)        \
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC64(fetch_and##name)                               \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       mvn     %[i], %[i]\n"                                   \
-       "       ldclr" #mb "    %[i], %[i], %[v]")                      \
-       : [i] "+&r" (x0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       "       ldclr" #mb "    %[i], %[i], %[v]"                       \
+       : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return x0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC64_FETCH_OP_AND(_relaxed,   )
@@ -335,42 +248,29 @@ ATOMIC64_FETCH_OP_AND(        , al, "memory")
 
 #undef ATOMIC64_FETCH_OP_AND
 
-static inline void arch_atomic64_sub(s64 i, atomic64_t *v)
+static inline void __lse_atomic64_sub(s64 i, atomic64_t *v)
 {
-       register s64 x0 asm ("x0") = i;
-       register atomic64_t *x1 asm ("x1") = v;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       __LL_SC_ATOMIC64(sub)
-       __nops(1),
-       /* LSE atomics */
+       asm volatile(
        "       neg     %[i], %[i]\n"
-       "       stadd   %[i], %[v]")
-       : [i] "+&r" (x0), [v] "+Q" (v->counter)
-       : "r" (x1)
-       : __LL_SC_CLOBBERS);
+       "       stadd   %[i], %[v]"
+       : [i] "+&r" (i), [v] "+Q" (v->counter)
+       : "r" (v));
 }
 
 #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...)                                \
-static inline s64 arch_atomic64_sub_return##name(s64 i, atomic64_t *v) \
+static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v)       \
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
+       unsigned long tmp;                                              \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC64(sub_return##name)                              \
-       __nops(2),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       neg     %[i], %[i]\n"                                   \
-       "       ldadd" #mb "    %[i], x30, %[v]\n"                      \
-       "       add     %[i], %[i], x30")                               \
-       : [i] "+&r" (x0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       "       ldadd" #mb "    %[i], %x[tmp], %[v]\n"                  \
+       "       add     %[i], %[i], %x[tmp]"                            \
+       : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)       \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return x0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC64_OP_SUB_RETURN(_relaxed,   )
@@ -381,23 +281,16 @@ ATOMIC64_OP_SUB_RETURN(        , al, "memory")
 #undef ATOMIC64_OP_SUB_RETURN
 
 #define ATOMIC64_FETCH_OP_SUB(name, mb, cl...)                         \
-static inline s64 arch_atomic64_fetch_sub##name(s64 i, atomic64_t *v)  \
+static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v)        \
 {                                                                      \
-       register s64 x0 asm ("x0") = i;                                 \
-       register atomic64_t *x1 asm ("x1") = v;                         \
-                                                                       \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_ATOMIC64(fetch_sub##name)                               \
-       __nops(1),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       neg     %[i], %[i]\n"                                   \
-       "       ldadd" #mb "    %[i], %[i], %[v]")                      \
-       : [i] "+&r" (x0), [v] "+Q" (v->counter)                         \
-       : "r" (x1)                                                      \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       "       ldadd" #mb "    %[i], %[i], %[v]"                       \
+       : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
+       : "r" (v)                                                       \
+       : cl);                                                          \
                                                                        \
-       return x0;                                                      \
+       return i;                                                       \
 }
 
 ATOMIC64_FETCH_OP_SUB(_relaxed,   )
@@ -407,54 +300,44 @@ ATOMIC64_FETCH_OP_SUB(        , al, "memory")
 
 #undef ATOMIC64_FETCH_OP_SUB
 
-static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
+static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v)
 {
-       register long x0 asm ("x0") = (long)v;
-
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-       /* LL/SC */
-       __LL_SC_ATOMIC64(dec_if_positive)
-       __nops(6),
-       /* LSE atomics */
-       "1:     ldr     x30, %[v]\n"
-       "       subs    %[ret], x30, #1\n"
+       unsigned long tmp;
+
+       asm volatile(
+       "1:     ldr     %x[tmp], %[v]\n"
+       "       subs    %[ret], %x[tmp], #1\n"
        "       b.lt    2f\n"
-       "       casal   x30, %[ret], %[v]\n"
-       "       sub     x30, x30, #1\n"
-       "       sub     x30, x30, %[ret]\n"
-       "       cbnz    x30, 1b\n"
-       "2:")
-       : [ret] "+&r" (x0), [v] "+Q" (v->counter)
+       "       casal   %x[tmp], %[ret], %[v]\n"
+       "       sub     %x[tmp], %x[tmp], #1\n"
+       "       sub     %x[tmp], %x[tmp], %[ret]\n"
+       "       cbnz    %x[tmp], 1b\n"
+       "2:"
+       : [ret] "+&r" (v), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)
        :
-       : __LL_SC_CLOBBERS, "cc", "memory");
+       : "cc", "memory");
 
-       return x0;
+       return (long)v;
 }
 
-#undef __LL_SC_ATOMIC64
-
-#define __LL_SC_CMPXCHG(op)    __LL_SC_CALL(__cmpxchg_case_##op)
-
 #define __CMPXCHG_CASE(w, sfx, name, sz, mb, cl...)                    \
-static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr,      \
+static inline u##sz __lse__cmpxchg_case_##name##sz(volatile void *ptr, \
                                              u##sz old,                \
                                              u##sz new)                \
 {                                                                      \
        register unsigned long x0 asm ("x0") = (unsigned long)ptr;      \
        register u##sz x1 asm ("x1") = old;                             \
        register u##sz x2 asm ("x2") = new;                             \
+       unsigned long tmp;                                              \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_CMPXCHG(name##sz)                                       \
-       __nops(2),                                                      \
-       /* LSE atomics */                                               \
-       "       mov     " #w "30, %" #w "[old]\n"                       \
-       "       cas" #mb #sfx "\t" #w "30, %" #w "[new], %[v]\n"        \
-       "       mov     %" #w "[ret], " #w "30")                        \
-       : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr)             \
+       asm volatile(                                                   \
+       "       mov     %" #w "[tmp], %" #w "[old]\n"                   \
+       "       cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n"    \
+       "       mov     %" #w "[ret], %" #w "[tmp]"                     \
+       : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr),            \
+         [tmp] "=&r" (tmp)                                             \
        : [old] "r" (x1), [new] "r" (x2)                                \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       : cl);                                                          \
                                                                        \
        return x0;                                                      \
 }
@@ -476,13 +359,10 @@ __CMPXCHG_CASE(w, h,  mb_, 16, al, "memory")
 __CMPXCHG_CASE(w,  ,  mb_, 32, al, "memory")
 __CMPXCHG_CASE(x,  ,  mb_, 64, al, "memory")
 
-#undef __LL_SC_CMPXCHG
 #undef __CMPXCHG_CASE
 
-#define __LL_SC_CMPXCHG_DBL(op)        __LL_SC_CALL(__cmpxchg_double##op)
-
 #define __CMPXCHG_DBL(name, mb, cl...)                                 \
-static inline long __cmpxchg_double##name(unsigned long old1,          \
+static inline long __lse__cmpxchg_double##name(unsigned long old1,     \
                                         unsigned long old2,            \
                                         unsigned long new1,            \
                                         unsigned long new2,            \
@@ -496,20 +376,16 @@ static inline long __cmpxchg_double##name(unsigned long old1,             \
        register unsigned long x3 asm ("x3") = new2;                    \
        register unsigned long x4 asm ("x4") = (unsigned long)ptr;      \
                                                                        \
-       asm volatile(ARM64_LSE_ATOMIC_INSN(                             \
-       /* LL/SC */                                                     \
-       __LL_SC_CMPXCHG_DBL(name)                                       \
-       __nops(3),                                                      \
-       /* LSE atomics */                                               \
+       asm volatile(                                                   \
        "       casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
        "       eor     %[old1], %[old1], %[oldval1]\n"                 \
        "       eor     %[old2], %[old2], %[oldval2]\n"                 \
-       "       orr     %[old1], %[old1], %[old2]")                     \
+       "       orr     %[old1], %[old1], %[old2]"                      \
        : [old1] "+&r" (x0), [old2] "+&r" (x1),                         \
          [v] "+Q" (*(unsigned long *)ptr)                              \
        : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),             \
          [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)              \
-       : __LL_SC_CLOBBERS, ##cl);                                      \
+       : cl);                                                          \
                                                                        \
        return x0;                                                      \
 }
@@ -517,7 +393,6 @@ static inline long __cmpxchg_double##name(unsigned long old1,               \
 __CMPXCHG_DBL(   ,   )
 __CMPXCHG_DBL(_mb, al, "memory")
 
-#undef __LL_SC_CMPXCHG_DBL
 #undef __CMPXCHG_DBL
 
 #endif /* __ASM_ATOMIC_LSE_H */
index 64eeaa4..43da6dd 100644 (file)
@@ -78,7 +78,7 @@ static inline u32 cache_type_cwg(void)
        return (read_cpuid_cachetype() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
 }
 
-#define __read_mostly __attribute__((__section__(".data..read_mostly")))
+#define __read_mostly __section(.data..read_mostly)
 
 static inline int cache_line_size_of_cpu(void)
 {
index 7a299a2..a1398f2 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/build_bug.h>
 #include <linux/compiler.h>
 
-#include <asm/atomic.h>
 #include <asm/barrier.h>
 #include <asm/lse.h>
 
@@ -104,6 +103,50 @@ __XCHG_GEN(_mb)
 #define arch_xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__)
 #define arch_xchg(...)         __xchg_wrapper( _mb, __VA_ARGS__)
 
+#define __CMPXCHG_CASE(name, sz)                       \
+static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr,      \
+                                             u##sz old,                \
+                                             u##sz new)                \
+{                                                                      \
+       return __lse_ll_sc_body(_cmpxchg_case_##name##sz,               \
+                               ptr, old, new);                         \
+}
+
+__CMPXCHG_CASE(    ,  8)
+__CMPXCHG_CASE(    , 16)
+__CMPXCHG_CASE(    , 32)
+__CMPXCHG_CASE(    , 64)
+__CMPXCHG_CASE(acq_,  8)
+__CMPXCHG_CASE(acq_, 16)
+__CMPXCHG_CASE(acq_, 32)
+__CMPXCHG_CASE(acq_, 64)
+__CMPXCHG_CASE(rel_,  8)
+__CMPXCHG_CASE(rel_, 16)
+__CMPXCHG_CASE(rel_, 32)
+__CMPXCHG_CASE(rel_, 64)
+__CMPXCHG_CASE(mb_,  8)
+__CMPXCHG_CASE(mb_, 16)
+__CMPXCHG_CASE(mb_, 32)
+__CMPXCHG_CASE(mb_, 64)
+
+#undef __CMPXCHG_CASE
+
+#define __CMPXCHG_DBL(name)                                            \
+static inline long __cmpxchg_double##name(unsigned long old1,          \
+                                        unsigned long old2,            \
+                                        unsigned long new1,            \
+                                        unsigned long new2,            \
+                                        volatile void *ptr)            \
+{                                                                      \
+       return __lse_ll_sc_body(_cmpxchg_double##name,                  \
+                               old1, old2, new1, new2, ptr);           \
+}
+
+__CMPXCHG_DBL(   )
+__CMPXCHG_DBL(_mb)
+
+#undef __CMPXCHG_DBL
+
 #define __CMPXCHG_GEN(sfx)                                             \
 static inline unsigned long __cmpxchg##sfx(volatile void *ptr,         \
                                           unsigned long old,           \
index fb8ad46..b0d53a2 100644 (file)
@@ -4,7 +4,6 @@
  */
 #ifndef __ASM_COMPAT_H
 #define __ASM_COMPAT_H
-#ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 
 /*
@@ -215,5 +214,4 @@ static inline int is_compat_thread(struct thread_info *thread)
 }
 
 #endif /* CONFIG_COMPAT */
-#endif /* __KERNEL__ */
 #endif /* __ASM_COMPAT_H */
index c09d633..86aabf1 100644 (file)
@@ -23,6 +23,8 @@
  * @cpu_boot:  Boots a cpu into the kernel.
  * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary
  *             synchronisation. Called from the cpu being booted.
+ * @cpu_can_disable: Determines whether a CPU can be disabled based on
+ *             mechanism-specific information.
  * @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific
  *             reason, which will cause the hot unplug to be aborted. Called
  *             from the cpu to be killed.
@@ -42,6 +44,7 @@ struct cpu_operations {
        int             (*cpu_boot)(unsigned int);
        void            (*cpu_postboot)(void);
 #ifdef CONFIG_HOTPLUG_CPU
+       bool            (*cpu_can_disable)(unsigned int cpu);
        int             (*cpu_disable)(unsigned int cpu);
        void            (*cpu_die)(unsigned int cpu);
        int             (*cpu_kill)(unsigned int cpu);
index c96ffa4..9cde5d2 100644 (file)
@@ -289,9 +289,16 @@ struct arm64_cpu_capabilities {
        u16 type;
        bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
        /*
-        * Take the appropriate actions to enable this capability for this CPU.
-        * For each successfully booted CPU, this method is called for each
-        * globally detected capability.
+        * Take the appropriate actions to configure this capability
+        * for this CPU. If the capability is detected by the kernel
+        * this will be called on all the CPUs in the system,
+        * including the hotplugged CPUs, regardless of whether the
+        * capability is available on that specific CPU. This is
+        * useful for some capabilities (e.g, working around CPU
+        * errata), where all the CPUs must take some action (e.g,
+        * changing system control/configuration). Thus, if an action
+        * is required only if the CPU has the capability, then the
+        * routine must check it before taking any action.
         */
        void (*cpu_enable)(const struct arm64_cpu_capabilities *cap);
        union {
@@ -363,21 +370,6 @@ cpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
        return false;
 }
 
-/*
- * Take appropriate action for all matching entries in the shared capability
- * entry.
- */
-static inline void
-cpucap_multi_entry_cap_cpu_enable(const struct arm64_cpu_capabilities *entry)
-{
-       const struct arm64_cpu_capabilities *caps;
-
-       for (caps = entry->match_list; caps->matches; caps++)
-               if (caps->matches(caps, SCOPE_LOCAL_CPU) &&
-                   caps->cpu_enable)
-                       caps->cpu_enable(caps);
-}
-
 extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
 extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
 extern struct static_key_false arm64_const_caps_ready;
index e7d4663..b1454d1 100644 (file)
 #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
                             MIDR_ARCHITECTURE_MASK)
 
-#define MIDR_IS_CPU_MODEL_RANGE(midr, model, rv_min, rv_max)           \
-({                                                                     \
-       u32 _model = (midr) & MIDR_CPU_MODEL_MASK;                      \
-       u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK);     \
-                                                                       \
-       _model == (model) && rv >= (rv_min) && rv <= (rv_max);          \
- })
-
 #define ARM_CPU_IMP_ARM                        0x41
 #define ARM_CPU_IMP_APM                        0x50
 #define ARM_CPU_IMP_CAVIUM             0x43
@@ -159,10 +151,19 @@ struct midr_range {
 #define MIDR_REV(m, v, r) MIDR_RANGE(m, v, r, v, r)
 #define MIDR_ALL_VERSIONS(m) MIDR_RANGE(m, 0, 0, 0xf, 0xf)
 
+static inline bool midr_is_cpu_model_range(u32 midr, u32 model, u32 rv_min,
+                                          u32 rv_max)
+{
+       u32 _model = midr & MIDR_CPU_MODEL_MASK;
+       u32 rv = midr & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK);
+
+       return _model == model && rv >= rv_min && rv <= rv_max;
+}
+
 static inline bool is_midr_in_range(u32 midr, struct midr_range const *range)
 {
-       return MIDR_IS_CPU_MODEL_RANGE(midr, range->model,
-                                range->rv_min, range->rv_max);
+       return midr_is_cpu_model_range(midr, range->model,
+                                      range->rv_min, range->rv_max);
 }
 
 static inline bool
index d8ec5bb..7619f47 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_DEBUG_MONITORS_H
 #define __ASM_DEBUG_MONITORS_H
 
-#ifdef __KERNEL__
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <asm/brk-imm.h>
@@ -128,5 +126,4 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs)
 int aarch32_break_handler(struct pt_regs *regs);
 
 #endif /* __ASSEMBLY */
-#endif /* __KERNEL__ */
 #endif /* __ASM_DEBUG_MONITORS_H */
index bdcb092..fb3e504 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_DMA_MAPPING_H
 #define __ASM_DMA_MAPPING_H
 
-#ifdef __KERNEL__
-
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 
@@ -27,5 +25,4 @@ static inline bool is_device_dma_coherent(struct device *dev)
        return dev->dma_coherent;
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_DMA_MAPPING_H */
index 76a1447..b54d3a8 100644 (file)
@@ -79,7 +79,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
 
 /*
  * On arm64, we have to ensure that the initrd ends up in the linear region,
- * which is a 1 GB aligned region of size '1UL << (VA_BITS - 1)' that is
+ * which is a 1 GB aligned region of size '1UL << (VA_BITS_MIN - 1)' that is
  * guaranteed to cover the kernel Image.
  *
  * Since the EFI stub is part of the kernel Image, we can relax the
@@ -90,7 +90,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
 static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
                                                    unsigned long image_addr)
 {
-       return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS - 1));
+       return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));
 }
 
 #define efi_call_early(f, ...)         sys_table_arg->boottime->f(__VA_ARGS__)
index 65ac184..cb29253 100644 (file)
@@ -34,7 +34,8 @@
 #define ESR_ELx_EC_SMC64       (0x17)  /* EL2 and above */
 #define ESR_ELx_EC_SYS64       (0x18)
 #define ESR_ELx_EC_SVE         (0x19)
-/* Unallocated EC: 0x1A - 0x1E */
+#define ESR_ELx_EC_ERET                (0x1a)  /* EL2 only */
+/* Unallocated EC: 0x1b - 0x1E */
 #define ESR_ELx_EC_IMP_DEF     (0x1f)  /* EL3 only */
 #define ESR_ELx_EC_IABT_LOW    (0x20)
 #define ESR_ELx_EC_IABT_CUR    (0x21)
index ed57b76..a17393f 100644 (file)
@@ -30,4 +30,6 @@ static inline u32 disr_to_esr(u64 disr)
        return esr;
 }
 
+asmlinkage void enter_from_user_mode(void);
+
 #endif /* __ASM_EXCEPTION_H */
index b6a2c35..59f10dd 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/stddef.h>
 #include <linux/types.h>
 
-#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+#ifdef CONFIG_COMPAT
 /* Masks for extracting the FPSR and FPCR from the FPSCR */
 #define VFP_FPSCR_STAT_MASK    0xf800009f
 #define VFP_FPSCR_CTRL_MASK    0x07f79f00
index 6211e31..6cc26a1 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_FUTEX_H
 #define __ASM_FUTEX_H
 
-#ifdef __KERNEL__
-
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 
@@ -129,5 +127,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
        return ret;
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_FUTEX_H */
index db9ab76..bc7aaed 100644 (file)
@@ -10,8 +10,6 @@
 #include <asm/sysreg.h>
 #include <asm/virt.h>
 
-#ifdef __KERNEL__
-
 struct arch_hw_breakpoint_ctrl {
        u32 __reserved  : 19,
        len             : 8,
@@ -156,5 +154,4 @@ static inline int get_num_wrps(void)
                                                ID_AA64DFR0_WRPS_SHIFT);
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_BREAKPOINT_H */
index 7ed9262..323cb30 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef __ASM_IO_H
 #define __ASM_IO_H
 
-#ifdef __KERNEL__
-
 #include <linux/types.h>
 
 #include <asm/byteorder.h>
@@ -97,7 +95,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 ({                                                                     \
        unsigned long tmp;                                              \
                                                                        \
-       rmb();                                                          \
+       dma_rmb();                                                              \
                                                                        \
        /*                                                              \
         * Create a dummy control dependency from the IO read to any    \
@@ -111,7 +109,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 })
 
 #define __io_par(v)            __iormb(v)
-#define __iowmb()              wmb()
+#define __iowmb()              dma_wmb()
 
 /*
  * Relaxed I/O memory access primitives. These follow the Device memory
@@ -165,14 +163,13 @@ extern void __memset_io(volatile void __iomem *, int, size_t);
  * I/O memory mapping functions.
  */
 extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot);
-extern void __iounmap(volatile void __iomem *addr);
+extern void iounmap(volatile void __iomem *addr);
 extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
 
 #define ioremap(addr, size)            __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_nocache(addr, size)    __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_wc(addr, size)         __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
 #define ioremap_wt(addr, size)         __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
-#define iounmap                                __iounmap
 
 /*
  * PCI configuration space mapping function.
@@ -207,5 +204,4 @@ extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
 
 extern int devmem_is_allowed(unsigned long pfn);
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_IO_H */
index 7872f26..1a59f0e 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_IRQFLAGS_H
 #define __ASM_IRQFLAGS_H
 
-#ifdef __KERNEL__
-
 #include <asm/alternative.h>
 #include <asm/ptrace.h>
 #include <asm/sysreg.h>
@@ -128,5 +126,4 @@ static inline void arch_local_irq_restore(unsigned long flags)
                : "memory");
 }
 
-#endif
-#endif
+#endif /* __ASM_IRQFLAGS_H */
index b52aacd..b0dc4ab 100644 (file)
  * KASAN_SHADOW_START: beginning of the kernel virtual addresses.
  * KASAN_SHADOW_END: KASAN_SHADOW_START + 1/N of kernel virtual addresses,
  * where N = (1 << KASAN_SHADOW_SCALE_SHIFT).
- */
-#define KASAN_SHADOW_START      (VA_START)
-#define KASAN_SHADOW_END        (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
-
-/*
+ *
+ * KASAN_SHADOW_OFFSET:
  * This value is used to map an address to the corresponding shadow
  * address by the following formula:
  *     shadow_addr = (address >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET
@@ -33,8 +30,8 @@
  *      KASAN_SHADOW_OFFSET = KASAN_SHADOW_END -
  *                             (1ULL << (64 - KASAN_SHADOW_SCALE_SHIFT))
  */
-#define KASAN_SHADOW_OFFSET     (KASAN_SHADOW_END - (1ULL << \
-                                       (64 - KASAN_SHADOW_SCALE_SHIFT)))
+#define _KASAN_SHADOW_START(va)        (KASAN_SHADOW_END - (1UL << ((va) - KASAN_SHADOW_SCALE_SHIFT)))
+#define KASAN_SHADOW_START      _KASAN_SHADOW_START(vabits_actual)
 
 void kasan_init(void);
 void kasan_copy_shadow(pgd_t *pgdir);
index 8262325..80b3882 100644 (file)
@@ -2,56 +2,47 @@
 #ifndef __ASM_LSE_H
 #define __ASM_LSE_H
 
+#include <asm/atomic_ll_sc.h>
+
 #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
 
 #include <linux/compiler_types.h>
 #include <linux/export.h>
+#include <linux/jump_label.h>
 #include <linux/stringify.h>
 #include <asm/alternative.h>
+#include <asm/atomic_lse.h>
 #include <asm/cpucaps.h>
 
-#ifdef __ASSEMBLER__
-
-.arch_extension        lse
-
-.macro alt_lse, llsc, lse
-       alternative_insn "\llsc", "\lse", ARM64_HAS_LSE_ATOMICS
-.endm
-
-#else  /* __ASSEMBLER__ */
-
 __asm__(".arch_extension       lse");
 
-/* Move the ll/sc atomics out-of-line */
-#define __LL_SC_INLINE         notrace
-#define __LL_SC_PREFIX(x)      __ll_sc_##x
-#define __LL_SC_EXPORT(x)      EXPORT_SYMBOL(__LL_SC_PREFIX(x))
+extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
+extern struct static_key_false arm64_const_caps_ready;
+
+static inline bool system_uses_lse_atomics(void)
+{
+       return (static_branch_likely(&arm64_const_caps_ready)) &&
+               static_branch_likely(&cpu_hwcap_keys[ARM64_HAS_LSE_ATOMICS]);
+}
 
-/* Macro for constructing calls to out-of-line ll/sc atomics */
-#define __LL_SC_CALL(op)       "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n"
-#define __LL_SC_CLOBBERS       "x16", "x17", "x30"
+#define __lse_ll_sc_body(op, ...)                                      \
+({                                                                     \
+       system_uses_lse_atomics() ?                                     \
+               __lse_##op(__VA_ARGS__) :                               \
+               __ll_sc_##op(__VA_ARGS__);                              \
+})
 
 /* In-line patching at runtime */
 #define ARM64_LSE_ATOMIC_INSN(llsc, lse)                               \
        ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS)
 
-#endif /* __ASSEMBLER__ */
 #else  /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
 
-#ifdef __ASSEMBLER__
-
-.macro alt_lse, llsc, lse
-       \llsc
-.endm
-
-#else  /* __ASSEMBLER__ */
+static inline bool system_uses_lse_atomics(void) { return false; }
 
-#define __LL_SC_INLINE         static inline
-#define __LL_SC_PREFIX(x)      x
-#define __LL_SC_EXPORT(x)
+#define __lse_ll_sc_body(op, ...)              __ll_sc_##op(__VA_ARGS__)
 
 #define ARM64_LSE_ATOMIC_INSN(llsc, lse)       llsc
 
-#endif /* __ASSEMBLER__ */
 #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
 #endif /* __ASM_LSE_H */
index fb04f10..b61b50b 100644 (file)
 
 #include <linux/compiler.h>
 #include <linux/const.h>
+#include <linux/sizes.h>
 #include <linux/types.h>
 #include <asm/bug.h>
 #include <asm/page-def.h>
-#include <linux/sizes.h>
 
 /*
  * Size of the PCI I/O space. This must remain a power of two so that
 /*
  * VMEMMAP_SIZE - allows the whole linear region to be covered by
  *                a struct page array
+ *
+ * If we are configured with a 52-bit kernel VA then our VMEMMAP_SIZE
+ * needs to cover the memory region from the beginning of the 52-bit
+ * PAGE_OFFSET all the way to PAGE_END for 48-bit. This allows us to
+ * keep a constant PAGE_OFFSET and "fallback" to using the higher end
+ * of the VMEMMAP where 52-bit support is not available in hardware.
  */
-#define VMEMMAP_SIZE (UL(1) << (VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT))
+#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \
+                       >> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT))
 
 /*
- * PAGE_OFFSET - the virtual address of the start of the linear map (top
- *              (VA_BITS - 1))
- * KIMAGE_VADDR - the virtual address of the start of the kernel image
+ * PAGE_OFFSET - the virtual address of the start of the linear map, at the
+ *               start of the TTBR1 address space.
+ * PAGE_END - the end of the linear map, where all other kernel mappings begin.
+ * KIMAGE_VADDR - the virtual address of the start of the kernel image.
  * VA_BITS - the maximum number of bits for virtual addresses.
- * VA_START - the first kernel virtual address.
  */
 #define VA_BITS                        (CONFIG_ARM64_VA_BITS)
-#define VA_START               (UL(0xffffffffffffffff) - \
-       (UL(1) << VA_BITS) + 1)
-#define PAGE_OFFSET            (UL(0xffffffffffffffff) - \
-       (UL(1) << (VA_BITS - 1)) + 1)
+#define _PAGE_OFFSET(va)       (-(UL(1) << (va)))
+#define PAGE_OFFSET            (_PAGE_OFFSET(VA_BITS))
 #define KIMAGE_VADDR           (MODULES_END)
-#define BPF_JIT_REGION_START   (VA_START + KASAN_SHADOW_SIZE)
+#define BPF_JIT_REGION_START   (KASAN_SHADOW_END)
 #define BPF_JIT_REGION_SIZE    (SZ_128M)
 #define BPF_JIT_REGION_END     (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE)
 #define MODULES_END            (MODULES_VADDR + MODULES_VSIZE)
 #define MODULES_VADDR          (BPF_JIT_REGION_END)
 #define MODULES_VSIZE          (SZ_128M)
-#define VMEMMAP_START          (PAGE_OFFSET - VMEMMAP_SIZE)
+#define VMEMMAP_START          (-VMEMMAP_SIZE - SZ_2M)
 #define PCI_IO_END             (VMEMMAP_START - SZ_2M)
 #define PCI_IO_START           (PCI_IO_END - PCI_IO_SIZE)
 #define FIXADDR_TOP            (PCI_IO_START - SZ_2M)
 
-#define KERNEL_START      _text
-#define KERNEL_END        _end
+#if VA_BITS > 48
+#define VA_BITS_MIN            (48)
+#else
+#define VA_BITS_MIN            (VA_BITS)
+#endif
+
+#define _PAGE_END(va)          (-(UL(1) << ((va) - 1)))
 
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+#define KERNEL_START           _text
+#define KERNEL_END             _end
+
+#ifdef CONFIG_ARM64_VA_BITS_52
 #define MAX_USER_VA_BITS       52
 #else
 #define MAX_USER_VA_BITS       VA_BITS
  * significantly, so double the (minimum) stack size when they are in use.
  */
 #ifdef CONFIG_KASAN
-#define KASAN_SHADOW_SIZE      (UL(1) << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
+#define KASAN_SHADOW_OFFSET    _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
+#define KASAN_SHADOW_END       ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) \
+                                       + KASAN_SHADOW_OFFSET)
 #define KASAN_THREAD_SHIFT     1
 #else
-#define KASAN_SHADOW_SIZE      (0)
 #define KASAN_THREAD_SHIFT     0
-#endif
+#define KASAN_SHADOW_END       (_PAGE_END(VA_BITS_MIN))
+#endif /* CONFIG_KASAN */
 
 #define MIN_THREAD_SHIFT       (14 + KASAN_THREAD_SHIFT)
 
  * 16 KB granule: 128 level 3 entries, with contiguous bit
  * 64 KB granule:  32 level 3 entries, with contiguous bit
  */
-#define SEGMENT_ALIGN                  SZ_2M
+#define SEGMENT_ALIGN          SZ_2M
 #else
 /*
  *  4 KB granule:  16 level 3 entries, with contiguous bit
  * 16 KB granule:   4 level 3 entries, without contiguous bit
  * 64 KB granule:   1 level 3 entry
  */
-#define SEGMENT_ALIGN                  SZ_64K
+#define SEGMENT_ALIGN          SZ_64K
 #endif
 
 /*
 #endif
 
 #ifndef __ASSEMBLY__
+extern u64                     vabits_actual;
+#define PAGE_END               (_PAGE_END(vabits_actual))
 
 #include <linux/bitops.h>
 #include <linux/mmdebug.h>
 
+extern s64                     physvirt_offset;
 extern s64                     memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
 #define PHYS_OFFSET            ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
@@ -176,9 +194,6 @@ static inline unsigned long kaslr_offset(void)
        return kimage_vaddr - KIMAGE_VADDR;
 }
 
-/* the actual size of a user virtual address */
-extern u64                     vabits_user;
-
 /*
  * Allow all memory at the discovery stage. We will clip it later.
  */
@@ -201,24 +216,24 @@ extern u64                        vabits_user;
  * pass on to access_ok(), for instance.
  */
 #define untagged_addr(addr)    \
-       ((__typeof__(addr))sign_extend64((u64)(addr), 55))
+       ((__force __typeof__(addr))sign_extend64((__force u64)(addr), 55))
 
 #ifdef CONFIG_KASAN_SW_TAGS
 #define __tag_shifted(tag)     ((u64)(tag) << 56)
-#define __tag_set(addr, tag)   (__typeof__(addr))( \
-               ((u64)(addr) & ~__tag_shifted(0xff)) | __tag_shifted(tag))
 #define __tag_reset(addr)      untagged_addr(addr)
 #define __tag_get(addr)                (__u8)((u64)(addr) >> 56)
 #else
+#define __tag_shifted(tag)     0UL
+#define __tag_reset(addr)      (addr)
+#define __tag_get(addr)                0
+#endif /* CONFIG_KASAN_SW_TAGS */
+
 static inline const void *__tag_set(const void *addr, u8 tag)
 {
-       return addr;
+       u64 __addr = (u64)addr & ~__tag_shifted(0xff);
+       return (const void *)(__addr | __tag_shifted(tag));
 }
 
-#define __tag_reset(addr)      (addr)
-#define __tag_get(addr)                0
-#endif
-
 /*
  * Physical vs virtual RAM address space conversion.  These are
  * private definitions which should NOT be used outside memory.h
@@ -227,19 +242,18 @@ static inline const void *__tag_set(const void *addr, u8 tag)
 
 
 /*
- * The linear kernel range starts in the middle of the virtual adddress
+ * The linear kernel range starts at the bottom of the virtual address
  * space. Testing the top bit for the start of the region is a
- * sufficient check.
+ * sufficient check and avoids having to worry about the tag.
  */
-#define __is_lm_address(addr)  (!!((addr) & BIT(VA_BITS - 1)))
+#define __is_lm_address(addr)  (!(((u64)addr) & BIT(vabits_actual - 1)))
 
-#define __lm_to_phys(addr)     (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
+#define __lm_to_phys(addr)     (((addr) + physvirt_offset))
 #define __kimg_to_phys(addr)   ((addr) - kimage_voffset)
 
 #define __virt_to_phys_nodebug(x) ({                                   \
-       phys_addr_t __x = (phys_addr_t)(x);                             \
-       __is_lm_address(__x) ? __lm_to_phys(__x) :                      \
-                              __kimg_to_phys(__x);                     \
+       phys_addr_t __x = (phys_addr_t)(__tag_reset(x));                \
+       __is_lm_address(__x) ? __lm_to_phys(__x) : __kimg_to_phys(__x); \
 })
 
 #define __pa_symbol_nodebug(x) __kimg_to_phys((phys_addr_t)(x))
@@ -250,9 +264,9 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
 #else
 #define __virt_to_phys(x)      __virt_to_phys_nodebug(x)
 #define __phys_addr_symbol(x)  __pa_symbol_nodebug(x)
-#endif
+#endif /* CONFIG_DEBUG_VIRTUAL */
 
-#define __phys_to_virt(x)      ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
+#define __phys_to_virt(x)      ((unsigned long)((x) - physvirt_offset))
 #define __phys_to_kimg(x)      ((unsigned long)((x) + kimage_voffset))
 
 /*
@@ -286,41 +300,38 @@ static inline void *phys_to_virt(phys_addr_t x)
 #define __pa_nodebug(x)                __virt_to_phys_nodebug((unsigned long)(x))
 #define __va(x)                        ((void *)__phys_to_virt((phys_addr_t)(x)))
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
-#define virt_to_pfn(x)      __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
-#define sym_to_pfn(x)      __phys_to_pfn(__pa_symbol(x))
+#define virt_to_pfn(x)         __phys_to_pfn(__virt_to_phys((unsigned long)(x)))
+#define sym_to_pfn(x)          __phys_to_pfn(__pa_symbol(x))
 
 /*
- *  virt_to_page(k)    convert a _valid_ virtual address to struct page *
- *  virt_addr_valid(k) indicates whether a virtual address is valid
+ *  virt_to_page(x)    convert a _valid_ virtual address to struct page *
+ *  virt_addr_valid(x) indicates whether a virtual address is valid
  */
 #define ARCH_PFN_OFFSET                ((unsigned long)PHYS_PFN_OFFSET)
 
 #if !defined(CONFIG_SPARSEMEM_VMEMMAP) || defined(CONFIG_DEBUG_VIRTUAL)
-#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define _virt_addr_valid(kaddr)        pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define virt_to_page(x)                pfn_to_page(virt_to_pfn(x))
 #else
-#define __virt_to_pgoff(kaddr) (((u64)(kaddr) & ~PAGE_OFFSET) / PAGE_SIZE * sizeof(struct page))
-#define __page_to_voff(kaddr)  (((u64)(kaddr) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page))
-
-#define page_to_virt(page)     ({                                      \
-       unsigned long __addr =                                          \
-               ((__page_to_voff(page)) | PAGE_OFFSET);                 \
-       const void *__addr_tag =                                        \
-               __tag_set((void *)__addr, page_kasan_tag(page));        \
-       ((void *)__addr_tag);                                           \
+#define page_to_virt(x)        ({                                              \
+       __typeof__(x) __page = x;                                       \
+       u64 __idx = ((u64)__page - VMEMMAP_START) / sizeof(struct page);\
+       u64 __addr = PAGE_OFFSET + (__idx * PAGE_SIZE);                 \
+       (void *)__tag_set((const void *)__addr, page_kasan_tag(__page));\
 })
 
-#define virt_to_page(vaddr)    ((struct page *)((__virt_to_pgoff(vaddr)) | VMEMMAP_START))
+#define virt_to_page(x)        ({                                              \
+       u64 __idx = (__tag_reset((u64)x) - PAGE_OFFSET) / PAGE_SIZE;    \
+       u64 __addr = VMEMMAP_START + (__idx * sizeof(struct page));     \
+       (struct page *)__addr;                                          \
+})
+#endif /* !CONFIG_SPARSEMEM_VMEMMAP || CONFIG_DEBUG_VIRTUAL */
 
-#define _virt_addr_valid(kaddr)        pfn_valid((((u64)(kaddr) & ~PAGE_OFFSET) \
-                                          + PHYS_OFFSET) >> PAGE_SHIFT)
-#endif
-#endif
+#define virt_addr_valid(addr)  ({                                      \
+       __typeof__(addr) __addr = addr;                                 \
+       __is_lm_address(__addr) && pfn_valid(virt_to_pfn(__addr));      \
+})
 
-#define _virt_addr_is_linear(kaddr)    \
-       (__tag_reset((u64)(kaddr)) >= PAGE_OFFSET)
-#define virt_addr_valid(kaddr)         \
-       (_virt_addr_is_linear(kaddr) && _virt_addr_valid(kaddr))
+#endif /* !ASSEMBLY */
 
 /*
  * Given that the GIC architecture permits ITS implementations that can only be
@@ -335,4 +346,4 @@ static inline void *phys_to_virt(phys_addr_t x)
 
 #include <asm-generic/memory_model.h>
 
-#endif
+#endif /* __ASM_MEMORY_H */
index fd61613..f217e32 100644 (file)
@@ -126,7 +126,7 @@ extern void init_mem_pgprot(void);
 extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
                               unsigned long virt, phys_addr_t size,
                               pgprot_t prot, bool page_mappings_only);
-extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
+extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
 extern void mark_linear_text_alias_ro(void);
 
 #define INIT_MM_CONTEXT(name)  \
index 7ed0adb..3827ff4 100644 (file)
@@ -63,7 +63,7 @@ extern u64 idmap_ptrs_per_pgd;
 
 static inline bool __cpu_uses_extended_idmap(void)
 {
-       if (IS_ENABLED(CONFIG_ARM64_USER_VA_BITS_52))
+       if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52))
                return false;
 
        return unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS));
@@ -95,7 +95,7 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
        isb();
 }
 
-#define cpu_set_default_tcr_t0sz()     __cpu_set_tcr_t0sz(TCR_T0SZ(VA_BITS))
+#define cpu_set_default_tcr_t0sz()     __cpu_set_tcr_t0sz(TCR_T0SZ(vabits_actual))
 #define cpu_set_idmap_tcr_t0sz()       __cpu_set_tcr_t0sz(idmap_t0sz)
 
 /*
index 9e69068..70b323c 100644 (file)
@@ -1,7 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef __ASM_PCI_H
 #define __ASM_PCI_H
-#ifdef __KERNEL__
 
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -35,5 +34,4 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 }
 #endif  /* CONFIG_PCI */
 
-#endif  /* __KERNEL__ */
 #endif  /* __ASM_PCI_H */
index db92950..3df60f9 100644 (file)
 #define TTBR_BADDR_MASK_52     (((UL(1) << 46) - 1) << 2)
 #endif
 
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+#ifdef CONFIG_ARM64_VA_BITS_52
 /* Must be at least 64-byte aligned to prevent corruption of the TTBR */
 #define TTBR1_BADDR_4852_OFFSET        (((UL(1) << (52 - PGDIR_SHIFT)) - \
                                 (UL(1) << (48 - PGDIR_SHIFT))) * 8)
index e09760e..470ba7a 100644 (file)
@@ -21,9 +21,7 @@
  *     and fixed mappings
  */
 #define VMALLOC_START          (MODULES_END)
-#define VMALLOC_END            (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
-
-#define vmemmap                        ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
+#define VMALLOC_END            (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
 #define FIRST_USER_ADDRESS     0UL
 
@@ -35,6 +33,8 @@
 #include <linux/mm_types.h>
 #include <linux/sched.h>
 
+extern struct page *vmemmap;
+
 extern void __pte_error(const char *file, int line, unsigned long val);
 extern void __pmd_error(const char *file, int line, unsigned long val);
 extern void __pud_error(const char *file, int line, unsigned long val);
@@ -220,8 +220,10 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
         * Only if the new pte is valid and kernel, otherwise TLB maintenance
         * or update_mmu_cache() have the necessary barriers.
         */
-       if (pte_valid_not_user(pte))
+       if (pte_valid_not_user(pte)) {
                dsb(ishst);
+               isb();
+       }
 }
 
 extern void __sync_icache_dcache(pte_t pteval);
@@ -484,8 +486,10 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 
        WRITE_ONCE(*pmdp, pmd);
 
-       if (pmd_valid(pmd))
+       if (pmd_valid(pmd)) {
                dsb(ishst);
+               isb();
+       }
 }
 
 static inline void pmd_clear(pmd_t *pmdp)
@@ -543,8 +547,10 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
 
        WRITE_ONCE(*pudp, pud);
 
-       if (pud_valid(pud))
+       if (pud_valid(pud)) {
                dsb(ishst);
+               isb();
+       }
 }
 
 static inline void pud_clear(pud_t *pudp)
@@ -602,6 +608,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 
        WRITE_ONCE(*pgdp, pgd);
        dsb(ishst);
+       isb();
 }
 
 static inline void pgd_clear(pgd_t *pgdp)
@@ -859,8 +866,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 
 #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
 
-#define kc_vaddr_to_offset(v)  ((v) & ~VA_START)
-#define kc_offset_to_vaddr(o)  ((o) | VA_START)
+#define kc_vaddr_to_offset(v)  ((v) & ~PAGE_END)
+#define kc_offset_to_vaddr(o)  ((o) | PAGE_END)
 
 #ifdef CONFIG_ARM64_PA_BITS_52
 #define phys_to_ttbr(addr)     (((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52)
index d328540..7a24bad 100644 (file)
@@ -69,7 +69,7 @@ extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
  * The EL0 pointer bits used by a pointer authentication code.
  * This is dependent on TBI0 being enabled, or bits 63:56 would also apply.
  */
-#define ptrauth_user_pac_mask()        GENMASK(54, vabits_user)
+#define ptrauth_user_pac_mask()        GENMASK(54, vabits_actual)
 
 /* Only valid for EL0 TTBR0 instruction pointers */
 static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr)
index 368d90a..a2ce65a 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef __ASM_PROCFNS_H
 #define __ASM_PROCFNS_H
 
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
 #include <asm/page.h>
@@ -25,5 +24,4 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 #include <asm/memory.h>
 
 #endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
 #endif /* __ASM_PROCFNS_H */
index 844e296..c67848c 100644 (file)
@@ -20,7 +20,6 @@
 #define NET_IP_ALIGN   0
 
 #ifndef __ASSEMBLY__
-#ifdef __KERNEL__
 
 #include <linux/build_bug.h>
 #include <linux/cache.h>
@@ -42,8 +41,8 @@
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
  */
 
-#define DEFAULT_MAP_WINDOW_64  (UL(1) << VA_BITS)
-#define TASK_SIZE_64           (UL(1) << vabits_user)
+#define DEFAULT_MAP_WINDOW_64  (UL(1) << VA_BITS_MIN)
+#define TASK_SIZE_64           (UL(1) << vabits_actual)
 
 #ifdef CONFIG_COMPAT
 #if defined(CONFIG_ARM64_64K_PAGES) && defined(CONFIG_KUSER_HELPERS)
@@ -283,8 +282,6 @@ static inline void spin_lock_prefetch(const void *ptr)
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
-#endif
-
 extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */
 extern void __init minsigstksz_setup(void);
 
@@ -306,6 +303,14 @@ extern void __init minsigstksz_setup(void);
 /* PR_PAC_RESET_KEYS prctl */
 #define PAC_RESET_KEYS(tsk, arg)       ptrauth_prctl_reset_keys(tsk, arg)
 
+#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
+long set_tagged_addr_ctrl(unsigned long arg);
+long get_tagged_addr_ctrl(void);
+#define SET_TAGGED_ADDR_CTRL(arg)      set_tagged_addr_ctrl(arg)
+#define GET_TAGGED_ADDR_CTRL()         get_tagged_addr_ctrl()
+#endif
+
 /*
  * For CONFIG_GCC_PLUGIN_STACKLEAK
  *
index 1dcf63a..fbebb41 100644 (file)
@@ -301,6 +301,11 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
        return regs->regs[0];
 }
 
+static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
+{
+       regs->regs[0] = rc;
+}
+
 /**
  * regs_get_kernel_argument() - get Nth function argument in kernel
  * @regs:      pt_regs of that context
index bd43d1c..7e9f163 100644 (file)
@@ -5,7 +5,6 @@
 #ifndef __ASM_SIGNAL32_H
 #define __ASM_SIGNAL32_H
 
-#ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
@@ -79,5 +78,4 @@ static inline void compat_setup_restart_syscall(struct pt_regs *regs)
 {
 }
 #endif /* CONFIG_COMPAT */
-#endif /* __KERNEL__ */
 #endif /* __ASM_SIGNAL32_H */
index 06ebcfe..972d196 100644 (file)
 #define SYS_FAR_EL1                    sys_reg(3, 0, 6, 0, 0)
 #define SYS_PAR_EL1                    sys_reg(3, 0, 7, 4, 0)
 
+#define SYS_PAR_EL1_F                  BIT(1)
+#define SYS_PAR_EL1_FST                        GENMASK(6, 1)
+
 /*** Statistical Profiling Extension ***/
 /* ID registers */
 #define SYS_PMSIDR_EL1                 sys_reg(3, 0, 9, 9, 7)
 #define SCTLR_EL2_RES1 ((BIT(4))  | (BIT(5))  | (BIT(11)) | (BIT(16)) | \
                         (BIT(18)) | (BIT(22)) | (BIT(23)) | (BIT(28)) | \
                         (BIT(29)))
-#define SCTLR_EL2_RES0 ((BIT(6))  | (BIT(7))  | (BIT(8))  | (BIT(9))  | \
-                        (BIT(10)) | (BIT(13)) | (BIT(14)) | (BIT(15)) | \
-                        (BIT(17)) | (BIT(20)) | (BIT(24)) | (BIT(26)) | \
-                        (BIT(27)) | (BIT(30)) | (BIT(31)) | \
-                        (0xffffefffUL << 32))
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define ENDIAN_SET_EL2         SCTLR_ELx_EE
-#define ENDIAN_CLEAR_EL2       0
 #else
 #define ENDIAN_SET_EL2         0
-#define ENDIAN_CLEAR_EL2       SCTLR_ELx_EE
-#endif
-
-/* SCTLR_EL2 value used for the hyp-stub */
-#define SCTLR_EL2_SET  (SCTLR_ELx_IESB   | ENDIAN_SET_EL2   | SCTLR_EL2_RES1)
-#define SCTLR_EL2_CLEAR        (SCTLR_ELx_M      | SCTLR_ELx_A    | SCTLR_ELx_C   | \
-                        SCTLR_ELx_SA     | SCTLR_ELx_I    | SCTLR_ELx_WXN | \
-                        SCTLR_ELx_DSSBS | ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0)
-
-#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffffffffffffUL
-#error "Inconsistent SCTLR_EL2 set/clear bits"
 #endif
 
 /* SCTLR_EL1 specific flags. */
 
 #define SCTLR_EL1_RES1 ((BIT(11)) | (BIT(20)) | (BIT(22)) | (BIT(28)) | \
                         (BIT(29)))
-#define SCTLR_EL1_RES0  ((BIT(6))  | (BIT(10)) | (BIT(13)) | (BIT(17)) | \
-                        (BIT(27)) | (BIT(30)) | (BIT(31)) | \
-                        (0xffffefffUL << 32))
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
 #define ENDIAN_SET_EL1         (SCTLR_EL1_E0E | SCTLR_ELx_EE)
-#define ENDIAN_CLEAR_EL1       0
 #else
 #define ENDIAN_SET_EL1         0
-#define ENDIAN_CLEAR_EL1       (SCTLR_EL1_E0E | SCTLR_ELx_EE)
 #endif
 
 #define SCTLR_EL1_SET  (SCTLR_ELx_M    | SCTLR_ELx_C    | SCTLR_ELx_SA   |\
                         SCTLR_EL1_DZE  | SCTLR_EL1_UCT                   |\
                         SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
                         ENDIAN_SET_EL1 | SCTLR_EL1_UCI  | SCTLR_EL1_RES1)
-#define SCTLR_EL1_CLEAR        (SCTLR_ELx_A   | SCTLR_EL1_CP15BEN | SCTLR_EL1_ITD    |\
-                        SCTLR_EL1_UMA | SCTLR_ELx_WXN     | ENDIAN_CLEAR_EL1 |\
-                        SCTLR_ELx_DSSBS | SCTLR_EL1_NTWI  | SCTLR_EL1_RES0)
-
-#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffffffffffffUL
-#error "Inconsistent SCTLR_EL1 set/clear bits"
-#endif
 
 /* id_aa64isar0 */
 #define ID_AA64ISAR0_TS_SHIFT          52
index 180b34e..f0cec41 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef __ASM_THREAD_INFO_H
 #define __ASM_THREAD_INFO_H
 
-#ifdef __KERNEL__
-
 #include <linux/compiler.h>
 
 #ifndef __ASSEMBLY__
@@ -59,29 +57,18 @@ void arch_release_task_struct(struct task_struct *tsk);
 
 #endif
 
-/*
- * thread information flags:
- *  TIF_SYSCALL_TRACE  - syscall trace active
- *  TIF_SYSCALL_TRACEPOINT - syscall tracepoint for ftrace
- *  TIF_SYSCALL_AUDIT  - syscall auditing
- *  TIF_SECCOMP                - syscall secure computing
- *  TIF_SYSCALL_EMU     - syscall emulation active
- *  TIF_SIGPENDING     - signal pending
- *  TIF_NEED_RESCHED   - rescheduling necessary
- *  TIF_NOTIFY_RESUME  - callback before returning to user
- */
-#define TIF_SIGPENDING         0
-#define TIF_NEED_RESCHED       1
+#define TIF_SIGPENDING         0       /* signal pending */
+#define TIF_NEED_RESCHED       1       /* rescheduling necessary */
 #define TIF_NOTIFY_RESUME      2       /* callback before returning to user */
 #define TIF_FOREIGN_FPSTATE    3       /* CPU's FP state is not current's */
 #define TIF_UPROBE             4       /* uprobe breakpoint or singlestep */
 #define TIF_FSCHECK            5       /* Check FS is USER_DS on return */
 #define TIF_NOHZ               7
-#define TIF_SYSCALL_TRACE      8
-#define TIF_SYSCALL_AUDIT      9
-#define TIF_SYSCALL_TRACEPOINT 10
-#define TIF_SECCOMP            11
-#define TIF_SYSCALL_EMU                12
+#define TIF_SYSCALL_TRACE      8       /* syscall trace active */
+#define TIF_SYSCALL_AUDIT      9       /* syscall auditing */
+#define TIF_SYSCALL_TRACEPOINT 10      /* syscall tracepoint for ftrace */
+#define TIF_SECCOMP            11      /* syscall secure computing */
+#define TIF_SYSCALL_EMU                12      /* syscall emulation active */
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_FREEZE             19
 #define TIF_RESTORE_SIGMASK    20
@@ -90,6 +77,7 @@ void arch_release_task_struct(struct task_struct *tsk);
 #define TIF_SVE                        23      /* Scalable Vector Extension in use */
 #define TIF_SVE_VL_INHERIT     24      /* Inherit sve_vl_onexec across exec */
 #define TIF_SSBD               25      /* Wants SSB mitigation */
+#define TIF_TAGGED_ADDR                26      /* Allow tagged user addresses */
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
@@ -121,5 +109,4 @@ void arch_release_task_struct(struct task_struct *tsk);
        .addr_limit     = KERNEL_DS,                                    \
 }
 
-#endif /* __KERNEL__ */
 #endif /* __ASM_THREAD_INFO_H */
index 8af7a85..bc39490 100644 (file)
@@ -251,6 +251,7 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
        dsb(ishst);
        __tlbi(vaae1is, addr);
        dsb(ish);
+       isb();
 }
 #endif
 
index 0524f24..a4d945d 100644 (file)
@@ -4,29 +4,6 @@
 
 #include <linux/cpumask.h>
 
-struct cpu_topology {
-       int thread_id;
-       int core_id;
-       int package_id;
-       int llc_id;
-       cpumask_t thread_sibling;
-       cpumask_t core_sibling;
-       cpumask_t llc_sibling;
-};
-
-extern struct cpu_topology cpu_topology[NR_CPUS];
-
-#define topology_physical_package_id(cpu)      (cpu_topology[cpu].package_id)
-#define topology_core_id(cpu)          (cpu_topology[cpu].core_id)
-#define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
-#define topology_sibling_cpumask(cpu)  (&cpu_topology[cpu].thread_sibling)
-#define topology_llc_cpumask(cpu)      (&cpu_topology[cpu].llc_sibling)
-
-void init_cpu_topology(void);
-void store_cpu_topology(unsigned int cpuid);
-void remove_cpu_topology(unsigned int cpuid);
-const struct cpumask *cpu_coregroup_mask(int cpu);
-
 #ifdef CONFIG_NUMA
 
 struct pci_bus;
index 5a1c322..097d6bf 100644 (file)
@@ -62,6 +62,10 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
 {
        unsigned long ret, limit = current_thread_info()->addr_limit;
 
+       if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) &&
+           test_thread_flag(TIF_TAGGED_ADDR))
+               addr = untagged_addr(addr);
+
        __chk_user_ptr(addr);
        asm volatile(
        // A + B <= C + 1 for all A,B,C, in four easy steps:
@@ -215,7 +219,8 @@ static inline void uaccess_enable_not_uao(void)
 
 /*
  * Sanitise a uaccess pointer such that it becomes NULL if above the
- * current addr_limit.
+ * current addr_limit. In case the pointer is tagged (has the top byte set),
+ * untag the pointer before checking.
  */
 #define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
 static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
@@ -223,10 +228,11 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
        void __user *safe_ptr;
 
        asm volatile(
-       "       bics    xzr, %1, %2\n"
+       "       bics    xzr, %3, %2\n"
        "       csel    %0, %1, xzr, eq\n"
        : "=&r" (safe_ptr)
-       : "r" (ptr), "r" (current_thread_info()->addr_limit)
+       : "r" (ptr), "r" (current_thread_info()->addr_limit),
+         "r" (untagged_addr(ptr))
        : "cc");
 
        csdb();
index 9c15e0a..0746842 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_VDSO_H
 #define __ASM_VDSO_H
 
-#ifdef __KERNEL__
-
 /*
  * Default link address for the vDSO.
  * Since we randomise the VDSO mapping, there's little point in trying
@@ -28,6 +26,4 @@
 
 #endif /* !__ASSEMBLY__ */
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_VDSO_H */
index ba6dbc3..1f38bf3 100644 (file)
@@ -5,8 +5,6 @@
 #ifndef __ASM_VDSO_DATAPAGE_H
 #define __ASM_VDSO_DATAPAGE_H
 
-#ifdef __KERNEL__
-
 #ifndef __ASSEMBLY__
 
 struct vdso_data {
@@ -32,6 +30,4 @@ struct vdso_data {
 
 #endif /* !__ASSEMBLY__ */
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_VDSO_DATAPAGE_H */
diff --git a/arch/arm64/include/uapi/asm/stat.h b/arch/arm64/include/uapi/asm/stat.h
deleted file mode 100644 (file)
index 313325f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#include <asm-generic/stat.h>
index d19d14b..9323bcc 100644 (file)
@@ -184,9 +184,17 @@ static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
-       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI),
-       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI),
+       /*
+        * We already refuse to boot CPUs that don't support our configured
+        * page size, so we can only detect mismatches for a page size other
+        * than the one we're currently using. Unfortunately, SoCs like this
+        * exist in the wild so, even though we don't like it, we'll have to go
+        * along with it and treat them as non-strict.
+        */
+       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN4_SHIFT, 4, ID_AA64MMFR0_TGRAN4_NI),
+       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN64_SHIFT, 4, ID_AA64MMFR0_TGRAN64_NI),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_TGRAN16_SHIFT, 4, ID_AA64MMFR0_TGRAN16_NI),
+
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_BIGENDEL0_SHIFT, 4, 0),
        /* Linux shouldn't care about secure memory */
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_SNSMEM_SHIFT, 4, 0),
@@ -886,7 +894,7 @@ static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int _
        u32 midr = read_cpuid_id();
 
        /* Cavium ThunderX pass 1.x and 2.x */
-       return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
+       return midr_is_cpu_model_range(midr, MIDR_THUNDERX,
                MIDR_CPU_VAR_REV(0, 0),
                MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
 }
index d104817..e4d6af2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/psci.h>
 
 #include <asm/cpuidle.h>
 #include <asm/cpu_ops.h>
@@ -46,17 +47,58 @@ int arm_cpuidle_suspend(int index)
 
 #define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags))
 
+static int psci_acpi_cpu_init_idle(unsigned int cpu)
+{
+       int i, count;
+       struct acpi_lpi_state *lpi;
+       struct acpi_processor *pr = per_cpu(processors, cpu);
+
+       /*
+        * If the PSCI cpu_suspend function hook has not been initialized
+        * idle states must not be enabled, so bail out
+        */
+       if (!psci_ops.cpu_suspend)
+               return -EOPNOTSUPP;
+
+       if (unlikely(!pr || !pr->flags.has_lpi))
+               return -EINVAL;
+
+       count = pr->power.count - 1;
+       if (count <= 0)
+               return -ENODEV;
+
+       for (i = 0; i < count; i++) {
+               u32 state;
+
+               lpi = &pr->power.lpi_states[i + 1];
+               /*
+                * Only bits[31:0] represent a PSCI power_state while
+                * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification
+                */
+               state = lpi->address;
+               if (!psci_power_state_is_valid(state)) {
+                       pr_warn("Invalid PSCI power state %#x\n", state);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 int acpi_processor_ffh_lpi_probe(unsigned int cpu)
 {
-       return arm_cpuidle_init(cpu);
+       return psci_acpi_cpu_init_idle(cpu);
 }
 
 int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
 {
+       u32 state = lpi->address;
+
        if (ARM64_LPI_IS_RETENTION_STATE(lpi->arch_flags))
-               return CPU_PM_CPU_IDLE_ENTER_RETENTION(arm_cpuidle_suspend,
-                                               lpi->index);
+               return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(psci_cpu_suspend_enter,
+                                               lpi->index, state);
        else
-               return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, lpi->index);
+               return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter,
+                                            lpi->index, state);
 }
 #endif
index 876055e..05933c0 100644 (file)
@@ -33,7 +33,7 @@
 DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
 static struct cpuinfo_arm64 boot_cpu_data;
 
-static char *icache_policy_str[] = {
+static const char *icache_policy_str[] = {
        [0 ... ICACHE_POLICY_PIPT]      = "RESERVED/UNKNOWN",
        [ICACHE_POLICY_VIPT]            = "VIPT",
        [ICACHE_POLICY_PIPT]            = "PIPT",
index 320a30d..84a8227 100644 (file)
@@ -30,9 +30,9 @@
  * Context tracking subsystem.  Used to instrument transitions
  * between user and kernel mode.
  */
-       .macro ct_user_exit
+       .macro ct_user_exit_irqoff
 #ifdef CONFIG_CONTEXT_TRACKING
-       bl      context_tracking_user_exit
+       bl      enter_from_user_mode
 #endif
        .endm
 
@@ -792,8 +792,8 @@ el0_cp15:
        /*
         * Trapped CP15 (MRC, MCR, MRRC, MCRR) instructions
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, x25
        mov     x1, sp
        bl      do_cp15instr
@@ -805,8 +805,8 @@ el0_da:
         * Data abort handling
         */
        mrs     x26, far_el1
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        clear_address_tag x0, x26
        mov     x1, x25
        mov     x2, sp
@@ -818,11 +818,11 @@ el0_ia:
         */
        mrs     x26, far_el1
        gic_prio_kentry_setup tmp=x0
+       ct_user_exit_irqoff
        enable_da_f
 #ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_off
 #endif
-       ct_user_exit
        mov     x0, x26
        mov     x1, x25
        mov     x2, sp
@@ -832,8 +832,8 @@ el0_fpsimd_acc:
        /*
         * Floating Point or Advanced SIMD access
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, x25
        mov     x1, sp
        bl      do_fpsimd_acc
@@ -842,8 +842,8 @@ el0_sve_acc:
        /*
         * Scalable Vector Extension access
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, x25
        mov     x1, sp
        bl      do_sve_acc
@@ -852,8 +852,8 @@ el0_fpsimd_exc:
        /*
         * Floating Point, Advanced SIMD or SVE exception
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, x25
        mov     x1, sp
        bl      do_fpsimd_exc
@@ -868,11 +868,11 @@ el0_sp_pc:
         * Stack or PC alignment exception handling
         */
        gic_prio_kentry_setup tmp=x0
+       ct_user_exit_irqoff
        enable_da_f
 #ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_off
 #endif
-       ct_user_exit
        mov     x0, x26
        mov     x1, x25
        mov     x2, sp
@@ -882,8 +882,8 @@ el0_undef:
        /*
         * Undefined instruction
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, sp
        bl      do_undefinstr
        b       ret_to_user
@@ -891,8 +891,8 @@ el0_sys:
        /*
         * System instructions, for trapped cache maintenance instructions
         */
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, x25
        mov     x1, sp
        bl      do_sysinstr
@@ -902,17 +902,18 @@ el0_dbg:
         * Debug exception handling
         */
        tbnz    x24, #0, el0_inv                // EL0 only
+       mrs     x24, far_el1
        gic_prio_kentry_setup tmp=x3
-       mrs     x0, far_el1
+       ct_user_exit_irqoff
+       mov     x0, x24
        mov     x1, x25
        mov     x2, sp
        bl      do_debug_exception
        enable_da_f
-       ct_user_exit
        b       ret_to_user
 el0_inv:
+       ct_user_exit_irqoff
        enable_daif
-       ct_user_exit
        mov     x0, sp
        mov     x1, #BAD_SYNC
        mov     x2, x25
@@ -925,13 +926,13 @@ el0_irq:
        kernel_entry 0
 el0_irq_naked:
        gic_prio_irq_setup pmr=x20, tmp=x0
+       ct_user_exit_irqoff
        enable_da_f
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_off
 #endif
 
-       ct_user_exit
 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
        tbz     x22, #55, 1f
        bl      do_el0_irq_bp_hardening
@@ -958,13 +959,14 @@ ENDPROC(el1_error)
 el0_error:
        kernel_entry 0
 el0_error_naked:
-       mrs     x1, esr_el1
+       mrs     x25, esr_el1
        gic_prio_kentry_setup tmp=x2
+       ct_user_exit_irqoff
        enable_dbg
        mov     x0, sp
+       mov     x1, x25
        bl      do_serror
        enable_da_f
-       ct_user_exit
        b       ret_to_user
 ENDPROC(el0_error)
 
index 1285c7b..1717732 100644 (file)
@@ -73,7 +73,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
        if (offset < -SZ_128M || offset >= SZ_128M) {
 #ifdef CONFIG_ARM64_MODULE_PLTS
-               struct plt_entry trampoline;
+               struct plt_entry trampoline, *dst;
                struct module *mod;
 
                /*
@@ -106,23 +106,27 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
                 * to check if the actual opcodes are in fact identical,
                 * regardless of the offset in memory so use memcmp() instead.
                 */
-               trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline);
-               if (memcmp(mod->arch.ftrace_trampoline, &trampoline,
-                          sizeof(trampoline))) {
-                       if (plt_entry_is_initialized(mod->arch.ftrace_trampoline)) {
+               dst = mod->arch.ftrace_trampoline;
+               trampoline = get_plt_entry(addr, dst);
+               if (memcmp(dst, &trampoline, sizeof(trampoline))) {
+                       if (plt_entry_is_initialized(dst)) {
                                pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
                                return -EINVAL;
                        }
 
                        /* point the trampoline to our ftrace entry point */
                        module_disable_ro(mod);
-                       *mod->arch.ftrace_trampoline = trampoline;
+                       *dst = trampoline;
                        module_enable_ro(mod, true);
 
-                       /* update trampoline before patching in the branch */
-                       smp_wmb();
+                       /*
+                        * Ensure updated trampoline is visible to instruction
+                        * fetch before we patch in the branch.
+                        */
+                       __flush_icache_range((unsigned long)&dst[0],
+                                            (unsigned long)&dst[1]);
                }
-               addr = (unsigned long)(void *)mod->arch.ftrace_trampoline;
+               addr = (unsigned long)dst;
 #else /* CONFIG_ARM64_MODULE_PLTS */
                return -EINVAL;
 #endif /* CONFIG_ARM64_MODULE_PLTS */
index 2cdacd1..989b194 100644 (file)
@@ -102,6 +102,8 @@ pe_header:
         *  x23        stext() .. start_kernel()  physical misalignment/KASLR offset
         *  x28        __create_page_tables()     callee preserved temp register
         *  x19/x20    __primary_switch()         callee preserved temp registers
+        *  x24        __primary_switch() .. relocate_kernel()
+        *                                        current RELR displacement
         */
 ENTRY(stext)
        bl      preserve_boot_args
@@ -308,15 +310,15 @@ __create_page_tables:
        adrp    x0, idmap_pg_dir
        adrp    x3, __idmap_text_start          // __pa(__idmap_text_start)
 
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
+#ifdef CONFIG_ARM64_VA_BITS_52
        mrs_s   x6, SYS_ID_AA64MMFR2_EL1
        and     x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
        mov     x5, #52
        cbnz    x6, 1f
 #endif
-       mov     x5, #VA_BITS
+       mov     x5, #VA_BITS_MIN
 1:
-       adr_l   x6, vabits_user
+       adr_l   x6, vabits_actual
        str     x5, [x6]
        dmb     sy
        dc      ivac, x6                // Invalidate potentially stale cache line
@@ -724,14 +726,22 @@ __secondary_switched:
 
        adr_l   x0, secondary_data
        ldr     x1, [x0, #CPU_BOOT_STACK]       // get secondary_data.stack
+       cbz     x1, __secondary_too_slow
        mov     sp, x1
        ldr     x2, [x0, #CPU_BOOT_TASK]
+       cbz     x2, __secondary_too_slow
        msr     sp_el0, x2
        mov     x29, #0
        mov     x30, #0
        b       secondary_start_kernel
 ENDPROC(__secondary_switched)
 
+__secondary_too_slow:
+       wfe
+       wfi
+       b       __secondary_too_slow
+ENDPROC(__secondary_too_slow)
+
 /*
  * The booting CPU updates the failed status @__early_cpu_boot_status,
  * with MMU turned off.
@@ -772,7 +782,7 @@ ENTRY(__enable_mmu)
        phys_to_ttbr x1, x1
        phys_to_ttbr x2, x2
        msr     ttbr0_el1, x2                   // load TTBR0
-       offset_ttbr1 x1
+       offset_ttbr1 x1, x3
        msr     ttbr1_el1, x1                   // load TTBR1
        isb
        msr     sctlr_el1, x0
@@ -789,8 +799,8 @@ ENTRY(__enable_mmu)
 ENDPROC(__enable_mmu)
 
 ENTRY(__cpu_secondary_check52bitva)
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
-       ldr_l   x0, vabits_user
+#ifdef CONFIG_ARM64_VA_BITS_52
+       ldr_l   x0, vabits_actual
        cmp     x0, #52
        b.ne    2f
 
@@ -834,14 +844,93 @@ __relocate_kernel:
 
 0:     cmp     x9, x10
        b.hs    1f
-       ldp     x11, x12, [x9], #24
-       ldr     x13, [x9, #-8]
-       cmp     w12, #R_AARCH64_RELATIVE
+       ldp     x12, x13, [x9], #24
+       ldr     x14, [x9, #-8]
+       cmp     w13, #R_AARCH64_RELATIVE
        b.ne    0b
-       add     x13, x13, x23                   // relocate
-       str     x13, [x11, x23]
+       add     x14, x14, x23                   // relocate
+       str     x14, [x12, x23]
        b       0b
-1:     ret
+
+1:
+#ifdef CONFIG_RELR
+       /*
+        * Apply RELR relocations.
+        *
+        * RELR is a compressed format for storing relative relocations. The
+        * encoded sequence of entries looks like:
+        * [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+        *
+        * i.e. start with an address, followed by any number of bitmaps. The
+        * address entry encodes 1 relocation. The subsequent bitmap entries
+        * encode up to 63 relocations each, at subsequent offsets following
+        * the last address entry.
+        *
+        * The bitmap entries must have 1 in the least significant bit. The
+        * assumption here is that an address cannot have 1 in lsb. Odd
+        * addresses are not supported. Any odd addresses are stored in the RELA
+        * section, which is handled above.
+        *
+        * Excluding the least significant bit in the bitmap, each non-zero
+        * bit in the bitmap represents a relocation to be applied to
+        * a corresponding machine word that follows the base address
+        * word. The second least significant bit represents the machine
+        * word immediately following the initial address, and each bit
+        * that follows represents the next word, in linear order. As such,
+        * a single bitmap can encode up to 63 relocations in a 64-bit object.
+        *
+        * In this implementation we store the address of the next RELR table
+        * entry in x9, the address being relocated by the current address or
+        * bitmap entry in x13 and the address being relocated by the current
+        * bit in x14.
+        *
+        * Because addends are stored in place in the binary, RELR relocations
+        * cannot be applied idempotently. We use x24 to keep track of the
+        * currently applied displacement so that we can correctly relocate if
+        * __relocate_kernel is called twice with non-zero displacements (i.e.
+        * if there is both a physical misalignment and a KASLR displacement).
+        */
+       ldr     w9, =__relr_offset              // offset to reloc table
+       ldr     w10, =__relr_size               // size of reloc table
+       add     x9, x9, x11                     // __va(.relr)
+       add     x10, x9, x10                    // __va(.relr) + sizeof(.relr)
+
+       sub     x15, x23, x24                   // delta from previous offset
+       cbz     x15, 7f                         // nothing to do if unchanged
+       mov     x24, x23                        // save new offset
+
+2:     cmp     x9, x10
+       b.hs    7f
+       ldr     x11, [x9], #8
+       tbnz    x11, #0, 3f                     // branch to handle bitmaps
+       add     x13, x11, x23
+       ldr     x12, [x13]                      // relocate address entry
+       add     x12, x12, x15
+       str     x12, [x13], #8                  // adjust to start of bitmap
+       b       2b
+
+3:     mov     x14, x13
+4:     lsr     x11, x11, #1
+       cbz     x11, 6f
+       tbz     x11, #0, 5f                     // skip bit if not set
+       ldr     x12, [x14]                      // relocate bit
+       add     x12, x12, x15
+       str     x12, [x14]
+
+5:     add     x14, x14, #8                    // move to next bit's address
+       b       4b
+
+6:     /*
+        * Move to the next bitmap's address. 8 is the word size, and 63 is the
+        * number of significant bits in a bitmap entry.
+        */
+       add     x13, x13, #(8 * 63)
+       b       2b
+
+7:
+#endif
+       ret
+
 ENDPROC(__relocate_kernel)
 #endif
 
@@ -854,6 +943,9 @@ __primary_switch:
        adrp    x1, init_pg_dir
        bl      __enable_mmu
 #ifdef CONFIG_RELOCATABLE
+#ifdef CONFIG_RELR
+       mov     x24, #0                         // no RELR displacement yet
+#endif
        bl      __relocate_kernel
 #ifdef CONFIG_RANDOMIZE_BASE
        ldr     x8, =__primary_switched
index 2f4a2ce..38bcd4d 100644 (file)
  * Even switching to our copied tables will cause a changed output address at
  * each stage of the walk.
  */
-.macro break_before_make_ttbr_switch zero_page, page_table, tmp
+.macro break_before_make_ttbr_switch zero_page, page_table, tmp, tmp2
        phys_to_ttbr \tmp, \zero_page
        msr     ttbr1_el1, \tmp
        isb
        tlbi    vmalle1
        dsb     nsh
        phys_to_ttbr \tmp, \page_table
-       offset_ttbr1 \tmp
+       offset_ttbr1 \tmp, \tmp2
        msr     ttbr1_el1, \tmp
        isb
 .endm
@@ -70,7 +70,7 @@ ENTRY(swsusp_arch_suspend_exit)
         * We execute from ttbr0, change ttbr1 to our copied linear map tables
         * with a break-before-make via the zero page
         */
-       break_before_make_ttbr_switch   x5, x0, x6
+       break_before_make_ttbr_switch   x5, x0, x6, x8
 
        mov     x21, x1
        mov     x30, x2
@@ -101,7 +101,7 @@ ENTRY(swsusp_arch_suspend_exit)
        dsb     ish             /* wait for PoU cleaning to finish */
 
        /* switch to the restored kernels page tables */
-       break_before_make_ttbr_switch   x25, x21, x6
+       break_before_make_ttbr_switch   x25, x21, x6, x8
 
        ic      ialluis
        dsb     ish
index 9341fcc..e0a7fce 100644 (file)
@@ -496,7 +496,7 @@ int swsusp_arch_resume(void)
                rc = -ENOMEM;
                goto out;
        }
-       rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, 0);
+       rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, PAGE_END);
        if (rc)
                goto out;
 
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
new file mode 100644 (file)
index 0000000..25a2a9b
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Linker script variables to be set after section resolution, as
+ * ld.lld does not like variables assigned before SECTIONS is processed.
+ */
+#ifndef __ARM64_KERNEL_IMAGE_VARS_H
+#define __ARM64_KERNEL_IMAGE_VARS_H
+
+#ifndef LINKER_SCRIPT
+#error This file should only be included in vmlinux.lds.S
+#endif
+
+#ifdef CONFIG_EFI
+
+__efistub_stext_offset = stext - _text;
+
+/*
+ * The EFI stub has its own symbol namespace prefixed by __efistub_, to
+ * isolate it from the kernel proper. The following symbols are legally
+ * accessed by the stub, so provide some aliases to make them accessible.
+ * Only include data symbols here, or text symbols of functions that are
+ * guaranteed to be safe when executed at another offset than they were
+ * linked at. The routines below are all implemented in assembler in a
+ * position independent manner
+ */
+__efistub_memcmp               = __pi_memcmp;
+__efistub_memchr               = __pi_memchr;
+__efistub_memcpy               = __pi_memcpy;
+__efistub_memmove              = __pi_memmove;
+__efistub_memset               = __pi_memset;
+__efistub_strlen               = __pi_strlen;
+__efistub_strnlen              = __pi_strnlen;
+__efistub_strcmp               = __pi_strcmp;
+__efistub_strncmp              = __pi_strncmp;
+__efistub_strrchr              = __pi_strrchr;
+__efistub___flush_dcache_area  = __pi___flush_dcache_area;
+
+#ifdef CONFIG_KASAN
+__efistub___memcpy             = __pi_memcpy;
+__efistub___memmove            = __pi_memmove;
+__efistub___memset             = __pi_memset;
+#endif
+
+__efistub__text                        = _text;
+__efistub__end                 = _end;
+__efistub__edata               = _edata;
+__efistub_screen_info          = screen_info;
+
+#endif
+
+#endif /* __ARM64_KERNEL_IMAGE_VARS_H */
index 2b85c0d..c7d38c6 100644 (file)
        DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
        DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
 
-#ifdef CONFIG_EFI
-
-/*
- * Use ABSOLUTE() to avoid ld.lld treating this as a relative symbol:
- * https://github.com/ClangBuiltLinux/linux/issues/561
- */
-__efistub_stext_offset = ABSOLUTE(stext - _text);
-
-/*
- * The EFI stub has its own symbol namespace prefixed by __efistub_, to
- * isolate it from the kernel proper. The following symbols are legally
- * accessed by the stub, so provide some aliases to make them accessible.
- * Only include data symbols here, or text symbols of functions that are
- * guaranteed to be safe when executed at another offset than they were
- * linked at. The routines below are all implemented in assembler in a
- * position independent manner
- */
-__efistub_memcmp               = __pi_memcmp;
-__efistub_memchr               = __pi_memchr;
-__efistub_memcpy               = __pi_memcpy;
-__efistub_memmove              = __pi_memmove;
-__efistub_memset               = __pi_memset;
-__efistub_strlen               = __pi_strlen;
-__efistub_strnlen              = __pi_strnlen;
-__efistub_strcmp               = __pi_strcmp;
-__efistub_strncmp              = __pi_strncmp;
-__efistub_strrchr              = __pi_strrchr;
-__efistub___flush_dcache_area  = __pi___flush_dcache_area;
-
-#ifdef CONFIG_KASAN
-__efistub___memcpy             = __pi_memcpy;
-__efistub___memmove            = __pi_memmove;
-__efistub___memset             = __pi_memset;
-#endif
-
-__efistub__text                        = _text;
-__efistub__end                 = _end;
-__efistub__edata               = _edata;
-__efistub_screen_info          = screen_info;
-
-#endif
-
 #endif /* __ARM64_KERNEL_IMAGE_H */
index 84b059e..d801a70 100644 (file)
@@ -26,7 +26,7 @@
 #define AARCH64_INSN_N_BIT     BIT(22)
 #define AARCH64_INSN_LSL_12    BIT(22)
 
-static int aarch64_insn_encoding_class[] = {
+static const int aarch64_insn_encoding_class[] = {
        AARCH64_INSN_CLS_UNKNOWN,
        AARCH64_INSN_CLS_UNKNOWN,
        AARCH64_INSN_CLS_UNKNOWN,
index 7080516..416f537 100644 (file)
@@ -62,9 +62,6 @@ out:
        return default_cmdline;
 }
 
-extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
-                                      pgprot_t prot);
-
 /*
  * This routine will be executed with the kernel mapped at its default virtual
  * address, and if it returns successfully, the kernel will be remapped, and
@@ -93,7 +90,7 @@ u64 __init kaslr_early_init(u64 dt_phys)
         * attempt at mapping the FDT in setup_machine()
         */
        early_fixmap_init();
-       fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
+       fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
        if (!fdt)
                return 0;
 
@@ -116,15 +113,15 @@ u64 __init kaslr_early_init(u64 dt_phys)
        /*
         * OK, so we are proceeding with KASLR enabled. Calculate a suitable
         * kernel image offset from the seed. Let's place the kernel in the
-        * middle half of the VMALLOC area (VA_BITS - 2), and stay clear of
+        * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
         * the lower and upper quarters to avoid colliding with other
         * allocations.
         * Even if we could randomize at page granularity for 16k and 64k pages,
         * let's always round to 2 MB so we don't interfere with the ability to
         * map using contiguous PTEs
         */
-       mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1);
-       offset = BIT(VA_BITS - 3) + (seed & mask);
+       mask = ((1UL << (VA_BITS_MIN - 2)) - 1) & ~(SZ_2M - 1);
+       offset = BIT(VA_BITS_MIN - 3) + (seed & mask);
 
        /* use the top 16 bits to randomize the linear region */
        memstart_offset_seed = seed >> 48;
index 2514fd6..29a9428 100644 (file)
@@ -84,7 +84,7 @@ static void *image_load(struct kimage *image,
 
        kbuf.buffer = kernel;
        kbuf.bufsz = kernel_len;
-       kbuf.mem = 0;
+       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
        kbuf.memsz = le64_to_cpu(h->image_size);
        text_offset = le64_to_cpu(h->text_offset);
        kbuf.buf_align = MIN_KIMG_ALIGN;
index 5887133..7b08bf9 100644 (file)
@@ -27,6 +27,8 @@
 #define FDT_PROP_INITRD_END    "linux,initrd-end"
 #define FDT_PROP_BOOTARGS      "bootargs"
 #define FDT_PROP_KASLR_SEED    "kaslr-seed"
+#define FDT_PROP_RNG_SEED      "rng-seed"
+#define RNG_SEED_SIZE          128
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
        &kexec_image_ops,
@@ -102,6 +104,19 @@ static int setup_dtb(struct kimage *image,
                                FDT_PROP_KASLR_SEED);
        }
 
+       /* add rng-seed */
+       if (rng_is_initialized()) {
+               u8 rng_seed[RNG_SEED_SIZE];
+               get_random_bytes(rng_seed, RNG_SEED_SIZE);
+               ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED, rng_seed,
+                               RNG_SEED_SIZE);
+               if (ret)
+                       goto out;
+       } else {
+               pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+                               FDT_PROP_RNG_SEED);
+       }
+
 out:
        if (ret)
                return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
@@ -110,7 +125,8 @@ out:
 }
 
 /*
- * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ * More space needed so that we can add initrd, bootargs, kaslr-seed, and
+ * rng-seed.
  */
 #define DTB_EXTRA_SPACE 0x1000
 
@@ -177,7 +193,7 @@ int load_other_segments(struct kimage *image,
        if (initrd) {
                kbuf.buffer = initrd;
                kbuf.bufsz = initrd_len;
-               kbuf.mem = 0;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
                kbuf.memsz = initrd_len;
                kbuf.buf_align = 0;
                /* within 1GB-aligned window of up to 32GB in size */
@@ -204,7 +220,7 @@ int load_other_segments(struct kimage *image,
        dtb_len = fdt_totalsize(dtb);
        kbuf.buffer = dtb;
        kbuf.bufsz = dtb_len;
-       kbuf.mem = 0;
+       kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
        kbuf.memsz = dtb_len;
        /* not across 2MB boundary */
        kbuf.buf_align = SZ_2M;
index 044c0ae..b182442 100644 (file)
@@ -302,7 +302,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
                /* sort by type, symbol index and addend */
                sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL);
 
-               if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0)
+               if (!str_has_prefix(secstrings + dstsec->sh_name, ".init"))
                        core_plts += count_plts(syms, rels, numrels,
                                                sechdrs[i].sh_info, dstsec);
                else
index 96e90e2..a0b4f1b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
+#include <linux/smp.h>
 
 /* ARMv8 Cortex-A53 specific event types. */
 #define ARMV8_A53_PERFCTR_PREF_LINEFILL                                0xC2
@@ -157,7 +158,6 @@ armv8pmu_events_sysfs_show(struct device *dev,
        return sprintf(page, "event=0x%03llx\n", pmu_attr->id);
 }
 
-#define ARMV8_EVENT_ATTR_RESOLVE(m) #m
 #define ARMV8_EVENT_ATTR(name, config) \
        PMU_EVENT_ATTR(name, armv8_event_attr_##name, \
                       config, armv8pmu_events_sysfs_show)
index f674f28..03689c0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/stddef.h>
+#include <linux/sysctl.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
 #include <linux/delay.h>
@@ -38,6 +39,7 @@
 #include <trace/events/power.h>
 #include <linux/percpu.h>
 #include <linux/thread_info.h>
+#include <linux/prctl.h>
 
 #include <asm/alternative.h>
 #include <asm/arch_gicv3.h>
@@ -307,11 +309,18 @@ static void tls_thread_flush(void)
        }
 }
 
+static void flush_tagged_addr_state(void)
+{
+       if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI))
+               clear_thread_flag(TIF_TAGGED_ADDR);
+}
+
 void flush_thread(void)
 {
        fpsimd_flush_thread();
        tls_thread_flush();
        flush_ptrace_hw_breakpoint(current);
+       flush_tagged_addr_state();
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -565,3 +574,70 @@ void arch_setup_new_exec(void)
 
        ptrauth_thread_init_user(current);
 }
+
+#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+/*
+ * Control the relaxed ABI allowing tagged user addresses into the kernel.
+ */
+static unsigned int tagged_addr_disabled;
+
+long set_tagged_addr_ctrl(unsigned long arg)
+{
+       if (is_compat_task())
+               return -EINVAL;
+       if (arg & ~PR_TAGGED_ADDR_ENABLE)
+               return -EINVAL;
+
+       /*
+        * Do not allow the enabling of the tagged address ABI if globally
+        * disabled via sysctl abi.tagged_addr_disabled.
+        */
+       if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
+               return -EINVAL;
+
+       update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
+
+       return 0;
+}
+
+long get_tagged_addr_ctrl(void)
+{
+       if (is_compat_task())
+               return -EINVAL;
+
+       if (test_thread_flag(TIF_TAGGED_ADDR))
+               return PR_TAGGED_ADDR_ENABLE;
+
+       return 0;
+}
+
+/*
+ * Global sysctl to disable the tagged user addresses support. This control
+ * only prevents the tagged address ABI enabling via prctl() and does not
+ * disable it for tasks that already opted in to the relaxed ABI.
+ */
+static int zero;
+static int one = 1;
+
+static struct ctl_table tagged_addr_sysctl_table[] = {
+       {
+               .procname       = "tagged_addr_disabled",
+               .mode           = 0644,
+               .data           = &tagged_addr_disabled,
+               .maxlen         = sizeof(int),
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+       { }
+};
+
+static int __init tagged_addr_init(void)
+{
+       if (!register_sysctl("abi", tagged_addr_sysctl_table))
+               return -EINVAL;
+       return 0;
+}
+
+core_initcall(tagged_addr_init);
+#endif /* CONFIG_ARM64_TAGGED_ADDR_ABI */
index 85ee7d0..c9f72b2 100644 (file)
@@ -46,6 +46,11 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
+static bool cpu_psci_cpu_can_disable(unsigned int cpu)
+{
+       return !psci_tos_resident_on(cpu);
+}
+
 static int cpu_psci_cpu_disable(unsigned int cpu)
 {
        /* Fail early if we don't have CPU_OFF support */
@@ -105,14 +110,11 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
 
 const struct cpu_operations cpu_psci_ops = {
        .name           = "psci",
-#ifdef CONFIG_CPU_IDLE
-       .cpu_init_idle  = psci_cpu_init_idle,
-       .cpu_suspend    = psci_cpu_suspend_enter,
-#endif
        .cpu_init       = cpu_psci_cpu_init,
        .cpu_prepare    = cpu_psci_cpu_prepare,
        .cpu_boot       = cpu_psci_cpu_boot,
 #ifdef CONFIG_HOTPLUG_CPU
+       .cpu_can_disable = cpu_psci_cpu_can_disable,
        .cpu_disable    = cpu_psci_cpu_disable,
        .cpu_die        = cpu_psci_cpu_die,
        .cpu_kill       = cpu_psci_cpu_kill,
index 3cf3b13..21176d0 100644 (file)
@@ -870,7 +870,7 @@ static int sve_set(struct task_struct *target,
                goto out;
 
        /*
-        * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by
+        * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by
         * sve_set_vector_length(), which will also validate them for us:
         */
        ret = sve_set_vector_length(target, header.vl,
index 9c4bad7..56f6645 100644 (file)
@@ -170,9 +170,13 @@ static void __init smp_build_mpidr_hash(void)
 
 static void __init setup_machine_fdt(phys_addr_t dt_phys)
 {
-       void *dt_virt = fixmap_remap_fdt(dt_phys);
+       int size;
+       void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
        const char *name;
 
+       if (dt_virt)
+               memblock_reserve(dt_phys, size);
+
        if (!dt_virt || !early_init_dt_scan(dt_virt)) {
                pr_crit("\n"
                        "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
@@ -184,6 +188,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
                        cpu_relax();
        }
 
+       /* Early fixups are done, map the FDT as read-only now */
+       fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
+
        name = of_flat_dt_get_machine_name();
        if (!name)
                return;
@@ -357,6 +364,15 @@ void __init setup_arch(char **cmdline_p)
        }
 }
 
+static inline bool cpu_can_disable(unsigned int cpu)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_can_disable)
+               return cpu_ops[cpu]->cpu_can_disable(cpu);
+#endif
+       return false;
+}
+
 static int __init topology_init(void)
 {
        int i;
@@ -366,7 +382,7 @@ static int __init topology_init(void)
 
        for_each_possible_cpu(i) {
                struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
-               cpu->hotpluggable = 1;
+               cpu->hotpluggable = cpu_can_disable(i);
                register_cpu(cpu, i);
        }
 
index 018a33e..dc9fe87 100644 (file)
@@ -123,7 +123,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
                 * time out.
                 */
                wait_for_completion_timeout(&cpu_running,
-                                           msecs_to_jiffies(1000));
+                                           msecs_to_jiffies(5000));
 
                if (!cpu_online(cpu)) {
                        pr_crit("CPU%u: failed to come online\n", cpu);
@@ -136,6 +136,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 
        secondary_data.task = NULL;
        secondary_data.stack = NULL;
+       __flush_dcache_area(&secondary_data, sizeof(secondary_data));
        status = READ_ONCE(secondary_data.status);
        if (ret && status) {
 
@@ -146,6 +147,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
                default:
                        pr_err("CPU%u: failed in unknown state : 0x%lx\n",
                                        cpu, status);
+                       cpus_stuck_in_kernel++;
                        break;
                case CPU_KILL_ME:
                        if (!op_cpu_kill(cpu)) {
index 76c2739..c8a3fee 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/smp_plat.h>
 
 extern void secondary_holding_pen(void);
-volatile unsigned long __section(".mmuoff.data.read")
+volatile unsigned long __section(.mmuoff.data.read)
 secondary_holding_pen_release = INVALID_HWID;
 
 static phys_addr_t cpu_release_addr[NR_CPUS];
index 0825c4a..fa9528d 100644 (file)
 #include <linux/acpi.h>
 #include <linux/arch_topology.h>
 #include <linux/cacheinfo.h>
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
 #include <linux/init.h>
 #include <linux/percpu.h>
-#include <linux/node.h>
-#include <linux/nodemask.h>
-#include <linux/of.h>
-#include <linux/sched.h>
-#include <linux/sched/topology.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-#include <linux/string.h>
 
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/topology.h>
 
-static int __init get_cpu_for_node(struct device_node *node)
-{
-       struct device_node *cpu_node;
-       int cpu;
-
-       cpu_node = of_parse_phandle(node, "cpu", 0);
-       if (!cpu_node)
-               return -1;
-
-       cpu = of_cpu_node_to_id(cpu_node);
-       if (cpu >= 0)
-               topology_parse_cpu_capacity(cpu_node, cpu);
-       else
-               pr_crit("Unable to find CPU node for %pOF\n", cpu_node);
-
-       of_node_put(cpu_node);
-       return cpu;
-}
-
-static int __init parse_core(struct device_node *core, int package_id,
-                            int core_id)
-{
-       char name[10];
-       bool leaf = true;
-       int i = 0;
-       int cpu;
-       struct device_node *t;
-
-       do {
-               snprintf(name, sizeof(name), "thread%d", i);
-               t = of_get_child_by_name(core, name);
-               if (t) {
-                       leaf = false;
-                       cpu = get_cpu_for_node(t);
-                       if (cpu >= 0) {
-                               cpu_topology[cpu].package_id = package_id;
-                               cpu_topology[cpu].core_id = core_id;
-                               cpu_topology[cpu].thread_id = i;
-                       } else {
-                               pr_err("%pOF: Can't get CPU for thread\n",
-                                      t);
-                               of_node_put(t);
-                               return -EINVAL;
-                       }
-                       of_node_put(t);
-               }
-               i++;
-       } while (t);
-
-       cpu = get_cpu_for_node(core);
-       if (cpu >= 0) {
-               if (!leaf) {
-                       pr_err("%pOF: Core has both threads and CPU\n",
-                              core);
-                       return -EINVAL;
-               }
-
-               cpu_topology[cpu].package_id = package_id;
-               cpu_topology[cpu].core_id = core_id;
-       } else if (leaf) {
-               pr_err("%pOF: Can't get CPU for leaf core\n", core);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int __init parse_cluster(struct device_node *cluster, int depth)
-{
-       char name[10];
-       bool leaf = true;
-       bool has_cores = false;
-       struct device_node *c;
-       static int package_id __initdata;
-       int core_id = 0;
-       int i, ret;
-
-       /*
-        * First check for child clusters; we currently ignore any
-        * information about the nesting of clusters and present the
-        * scheduler with a flat list of them.
-        */
-       i = 0;
-       do {
-               snprintf(name, sizeof(name), "cluster%d", i);
-               c = of_get_child_by_name(cluster, name);
-               if (c) {
-                       leaf = false;
-                       ret = parse_cluster(c, depth + 1);
-                       of_node_put(c);
-                       if (ret != 0)
-                               return ret;
-               }
-               i++;
-       } while (c);
-
-       /* Now check for cores */
-       i = 0;
-       do {
-               snprintf(name, sizeof(name), "core%d", i);
-               c = of_get_child_by_name(cluster, name);
-               if (c) {
-                       has_cores = true;
-
-                       if (depth == 0) {
-                               pr_err("%pOF: cpu-map children should be clusters\n",
-                                      c);
-                               of_node_put(c);
-                               return -EINVAL;
-                       }
-
-                       if (leaf) {
-                               ret = parse_core(c, package_id, core_id++);
-                       } else {
-                               pr_err("%pOF: Non-leaf cluster with core %s\n",
-                                      cluster, name);
-                               ret = -EINVAL;
-                       }
-
-                       of_node_put(c);
-                       if (ret != 0)
-                               return ret;
-               }
-               i++;
-       } while (c);
-
-       if (leaf && !has_cores)
-               pr_warn("%pOF: empty cluster\n", cluster);
-
-       if (leaf)
-               package_id++;
-
-       return 0;
-}
-
-static int __init parse_dt_topology(void)
-{
-       struct device_node *cn, *map;
-       int ret = 0;
-       int cpu;
-
-       cn = of_find_node_by_path("/cpus");
-       if (!cn) {
-               pr_err("No CPU information found in DT\n");
-               return 0;
-       }
-
-       /*
-        * When topology is provided cpu-map is essentially a root
-        * cluster with restricted subnodes.
-        */
-       map = of_get_child_by_name(cn, "cpu-map");
-       if (!map)
-               goto out;
-
-       ret = parse_cluster(map, 0);
-       if (ret != 0)
-               goto out_map;
-
-       topology_normalize_cpu_scale();
-
-       /*
-        * Check that all cores are in the topology; the SMP code will
-        * only mark cores described in the DT as possible.
-        */
-       for_each_possible_cpu(cpu)
-               if (cpu_topology[cpu].package_id == -1)
-                       ret = -EINVAL;
-
-out_map:
-       of_node_put(map);
-out:
-       of_node_put(cn);
-       return ret;
-}
-
-/*
- * cpu topology table
- */
-struct cpu_topology cpu_topology[NR_CPUS];
-EXPORT_SYMBOL_GPL(cpu_topology);
-
-const struct cpumask *cpu_coregroup_mask(int cpu)
-{
-       const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
-
-       /* Find the smaller of NUMA, core or LLC siblings */
-       if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
-               /* not numa in package, lets use the package siblings */
-               core_mask = &cpu_topology[cpu].core_sibling;
-       }
-       if (cpu_topology[cpu].llc_id != -1) {
-               if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask))
-                       core_mask = &cpu_topology[cpu].llc_sibling;
-       }
-
-       return core_mask;
-}
-
-static void update_siblings_masks(unsigned int cpuid)
-{
-       struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
-       int cpu;
-
-       /* update core and thread sibling masks */
-       for_each_online_cpu(cpu) {
-               cpu_topo = &cpu_topology[cpu];
-
-               if (cpuid_topo->llc_id == cpu_topo->llc_id) {
-                       cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling);
-                       cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling);
-               }
-
-               if (cpuid_topo->package_id != cpu_topo->package_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
-               cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
-
-               if (cpuid_topo->core_id != cpu_topo->core_id)
-                       continue;
-
-               cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
-               cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
-       }
-}
-
 void store_cpu_topology(unsigned int cpuid)
 {
        struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
@@ -296,60 +59,31 @@ topology_populated:
        update_siblings_masks(cpuid);
 }
 
-static void clear_cpu_topology(int cpu)
-{
-       struct cpu_topology *cpu_topo = &cpu_topology[cpu];
-
-       cpumask_clear(&cpu_topo->llc_sibling);
-       cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);
-
-       cpumask_clear(&cpu_topo->core_sibling);
-       cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
-       cpumask_clear(&cpu_topo->thread_sibling);
-       cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
-}
-
-static void __init reset_cpu_topology(void)
-{
-       unsigned int cpu;
-
-       for_each_possible_cpu(cpu) {
-               struct cpu_topology *cpu_topo = &cpu_topology[cpu];
-
-               cpu_topo->thread_id = -1;
-               cpu_topo->core_id = 0;
-               cpu_topo->package_id = -1;
-               cpu_topo->llc_id = -1;
-
-               clear_cpu_topology(cpu);
-       }
-}
-
-void remove_cpu_topology(unsigned int cpu)
+#ifdef CONFIG_ACPI
+static bool __init acpi_cpu_is_threaded(int cpu)
 {
-       int sibling;
+       int is_threaded = acpi_pptt_cpu_is_thread(cpu);
 
-       for_each_cpu(sibling, topology_core_cpumask(cpu))
-               cpumask_clear_cpu(cpu, topology_core_cpumask(sibling));
-       for_each_cpu(sibling, topology_sibling_cpumask(cpu))
-               cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
-       for_each_cpu(sibling, topology_llc_cpumask(cpu))
-               cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling));
+       /*
+        * if the PPTT doesn't have thread information, assume a homogeneous
+        * machine and return the current CPU's thread state.
+        */
+       if (is_threaded < 0)
+               is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
 
-       clear_cpu_topology(cpu);
+       return !!is_threaded;
 }
 
-#ifdef CONFIG_ACPI
 /*
  * Propagate the topology information of the processor_topology_node tree to the
  * cpu_topology array.
  */
-static int __init parse_acpi_topology(void)
+int __init parse_acpi_topology(void)
 {
-       bool is_threaded;
        int cpu, topology_id;
 
-       is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
+       if (acpi_disabled)
+               return 0;
 
        for_each_possible_cpu(cpu) {
                int i, cache_id;
@@ -358,7 +92,7 @@ static int __init parse_acpi_topology(void)
                if (topology_id < 0)
                        return topology_id;
 
-               if (is_threaded) {
+               if (acpi_cpu_is_threaded(cpu)) {
                        cpu_topology[cpu].thread_id = topology_id;
                        topology_id = find_acpi_cpu_topology(cpu, 1);
                        cpu_topology[cpu].core_id   = topology_id;
@@ -384,24 +118,6 @@ static int __init parse_acpi_topology(void)
 
        return 0;
 }
-
-#else
-static inline int __init parse_acpi_topology(void)
-{
-       return -EINVAL;
-}
 #endif
 
-void __init init_cpu_topology(void)
-{
-       reset_cpu_topology();
 
-       /*
-        * Discard anything that was parsed if we hit an error so we
-        * don't use partial information.
-        */
-       if (!acpi_disabled && parse_acpi_topology())
-               reset_cpu_topology();
-       else if (of_have_populated_dt() && parse_dt_topology())
-               reset_cpu_topology();
-}
index 32893b3..34739e8 100644 (file)
@@ -7,9 +7,11 @@
  */
 
 #include <linux/bug.h>
+#include <linux/context_tracking.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
 #include <linux/kallsyms.h>
+#include <linux/kprobes.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
@@ -511,7 +513,7 @@ struct sys64_hook {
        void (*handler)(unsigned int esr, struct pt_regs *regs);
 };
 
-static struct sys64_hook sys64_hooks[] = {
+static const struct sys64_hook sys64_hooks[] = {
        {
                .esr_mask = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_MASK,
                .esr_val = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_VAL,
@@ -636,7 +638,7 @@ static void compat_cntfrq_read_handler(unsigned int esr, struct pt_regs *regs)
        arm64_compat_skip_faulting_instruction(regs, 4);
 }
 
-static struct sys64_hook cp15_32_hooks[] = {
+static const struct sys64_hook cp15_32_hooks[] = {
        {
                .esr_mask = ESR_ELx_CP15_32_ISS_SYS_MASK,
                .esr_val = ESR_ELx_CP15_32_ISS_SYS_CNTFRQ,
@@ -656,7 +658,7 @@ static void compat_cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
        arm64_compat_skip_faulting_instruction(regs, 4);
 }
 
-static struct sys64_hook cp15_64_hooks[] = {
+static const struct sys64_hook cp15_64_hooks[] = {
        {
                .esr_mask = ESR_ELx_CP15_64_ISS_SYS_MASK,
                .esr_val = ESR_ELx_CP15_64_ISS_SYS_CNTVCT,
@@ -667,7 +669,7 @@ static struct sys64_hook cp15_64_hooks[] = {
 
 asmlinkage void __exception do_cp15instr(unsigned int esr, struct pt_regs *regs)
 {
-       struct sys64_hook *hook, *hook_base;
+       const struct sys64_hook *hook, *hook_base;
 
        if (!cp15_cond_valid(esr, regs)) {
                /*
@@ -707,7 +709,7 @@ asmlinkage void __exception do_cp15instr(unsigned int esr, struct pt_regs *regs)
 
 asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
 {
-       struct sys64_hook *hook;
+       const struct sys64_hook *hook;
 
        for (hook = sys64_hooks; hook->handler; hook++)
                if ((hook->esr_mask & esr) == hook->esr_val) {
@@ -744,6 +746,7 @@ static const char *esr_class_str[] = {
        [ESR_ELx_EC_SMC64]              = "SMC (AArch64)",
        [ESR_ELx_EC_SYS64]              = "MSR/MRS (AArch64)",
        [ESR_ELx_EC_SVE]                = "SVE",
+       [ESR_ELx_EC_ERET]               = "ERET/ERETAA/ERETAB",
        [ESR_ELx_EC_IMP_DEF]            = "EL3 IMP DEF",
        [ESR_ELx_EC_IABT_LOW]           = "IABT (lower EL)",
        [ESR_ELx_EC_IABT_CUR]           = "IABT (current EL)",
@@ -900,6 +903,13 @@ asmlinkage void do_serror(struct pt_regs *regs, unsigned int esr)
                nmi_exit();
 }
 
+asmlinkage void enter_from_user_mode(void)
+{
+       CT_WARN_ON(ct_state() != CONTEXT_USER);
+       user_exit_irqoff();
+}
+NOKPROBE_SYMBOL(enter_from_user_mode);
+
 void __pte_error(const char *file, int line, unsigned long val)
 {
        pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
index 7fa0083..aa76f72 100644 (file)
@@ -200,6 +200,15 @@ SECTIONS
        __rela_offset   = ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR);
        __rela_size     = SIZEOF(.rela.dyn);
 
+#ifdef CONFIG_RELR
+       .relr.dyn : ALIGN(8) {
+               *(.relr.dyn)
+       }
+
+       __relr_offset   = ABSOLUTE(ADDR(.relr.dyn) - KIMAGE_VADDR);
+       __relr_size     = SIZEOF(.relr.dyn);
+#endif
+
        . = ALIGN(SEGMENT_ALIGN);
        __initdata_end = .;
        __init_end = .;
@@ -245,6 +254,8 @@ SECTIONS
        HEAD_SYMBOLS
 }
 
+#include "image-vars.h"
+
 /*
  * The HYP init code and ID map text can't be longer than a page each,
  * and should not cross a page boundary.
index adaf266..bd978ad 100644 (file)
@@ -264,7 +264,7 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar)
        tmp = read_sysreg(par_el1);
        write_sysreg(par, par_el1);
 
-       if (unlikely(tmp & 1))
+       if (unlikely(tmp & SYS_PAR_EL1_F))
                return false; /* Translation failed, back to guest */
 
        /* Convert PAR to HPFAR format */
index acd8084..2cf7d4b 100644 (file)
@@ -29,25 +29,25 @@ static void compute_layout(void)
        int kva_msb;
 
        /* Where is my RAM region? */
-       hyp_va_msb  = idmap_addr & BIT(VA_BITS - 1);
-       hyp_va_msb ^= BIT(VA_BITS - 1);
+       hyp_va_msb  = idmap_addr & BIT(vabits_actual - 1);
+       hyp_va_msb ^= BIT(vabits_actual - 1);
 
        kva_msb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^
                        (u64)(high_memory - 1));
 
-       if (kva_msb == (VA_BITS - 1)) {
+       if (kva_msb == (vabits_actual - 1)) {
                /*
                 * No space in the address, let's compute the mask so
-                * that it covers (VA_BITS - 1) bits, and the region
+                * that it covers (vabits_actual - 1) bits, and the region
                 * bit. The tag stays set to zero.
                 */
-               va_mask  = BIT(VA_BITS - 1) - 1;
+               va_mask  = BIT(vabits_actual - 1) - 1;
                va_mask |= hyp_va_msb;
        } else {
                /*
                 * We do have some free bits to insert a random tag.
                 * Hyp VAs are now created from kernel linear map VAs
-                * using the following formula (with V == VA_BITS):
+                * using the following formula (with V == vabits_actual):
                 *
                 *  63 ... V |     V-1    | V-2 .. tag_lsb | tag_lsb - 1 .. 0
                 *  ---------------------------------------------------------
@@ -55,7 +55,7 @@ static void compute_layout(void)
                 */
                tag_lsb = kva_msb;
                va_mask = GENMASK_ULL(tag_lsb - 1, 0);
-               tag_val = get_random_long() & GENMASK_ULL(VA_BITS - 2, tag_lsb);
+               tag_val = get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb);
                tag_val |= hyp_va_msb;
                tag_val >>= tag_lsb;
        }
index 33c2a4a..c21b936 100644 (file)
@@ -11,25 +11,8 @@ CFLAGS_REMOVE_xor-neon.o     += -mgeneral-regs-only
 CFLAGS_xor-neon.o              += -ffreestanding
 endif
 
-# Tell the compiler to treat all general purpose registers (with the
-# exception of the IP registers, which are already handled by the caller
-# in case of a PLT) as callee-saved, which allows for efficient runtime
-# patching of the bl instruction in the caller with an atomic instruction
-# when supported by the CPU. Result and argument registers are handled
-# correctly, based on the function prototype.
-lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o
-CFLAGS_atomic_ll_sc.o  := -ffixed-x1 -ffixed-x2                        \
-                  -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6          \
-                  -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9           \
-                  -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12   \
-                  -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15   \
-                  -fcall-saved-x18 -fomit-frame-pointer
-CFLAGS_REMOVE_atomic_ll_sc.o := $(CC_FLAGS_FTRACE)
-GCOV_PROFILE_atomic_ll_sc.o    := n
-KASAN_SANITIZE_atomic_ll_sc.o  := n
-KCOV_INSTRUMENT_atomic_ll_sc.o := n
-UBSAN_SANITIZE_atomic_ll_sc.o  := n
-
 lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
 
 obj-$(CONFIG_CRC32) += crc32.o
+
+obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/arm64/lib/atomic_ll_sc.c b/arch/arm64/lib/atomic_ll_sc.c
deleted file mode 100644 (file)
index b0c538b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <asm/atomic.h>
-#define __ARM64_IN_ATOMIC_IMPL
-#include <asm/atomic_ll_sc.h>
diff --git a/arch/arm64/lib/error-inject.c b/arch/arm64/lib/error-inject.c
new file mode 100644 (file)
index 0000000..ed15021
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/error-injection.h>
+#include <linux/kprobes.h>
+
+void override_function_with_return(struct pt_regs *regs)
+{
+       /*
+        * 'regs' represents the state on entry of a predefined function in
+        * the kernel/module and which is captured on a kprobe.
+        *
+        * When kprobe returns back from exception it will override the end
+        * of probed function and directly return to the predefined
+        * function's caller.
+        */
+       instruction_pointer_set(regs, procedure_link_pointer(regs));
+}
+NOKPROBE_SYMBOL(override_function_with_return);
index 1d3f0b5..bd2b039 100644 (file)
@@ -14,9 +14,7 @@
 pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
                unsigned long attrs)
 {
-       if (!dev_is_dma_coherent(dev) || (attrs & DMA_ATTR_WRITE_COMBINE))
-               return pgprot_writecombine(prot);
-       return prot;
+       return pgprot_writecombine(prot);
 }
 
 void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
index 82b3a7f..93f9f77 100644 (file)
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptdump.h>
 
-static const struct addr_marker address_markers[] = {
+
+enum address_markers_idx {
+       PAGE_OFFSET_NR = 0,
+       PAGE_END_NR,
 #ifdef CONFIG_KASAN
-       { KASAN_SHADOW_START,           "Kasan shadow start" },
+       KASAN_START_NR,
+#endif
+};
+
+static struct addr_marker address_markers[] = {
+       { PAGE_OFFSET,                  "Linear Mapping start" },
+       { 0 /* PAGE_END */,             "Linear Mapping end" },
+#ifdef CONFIG_KASAN
+       { 0 /* KASAN_SHADOW_START */,   "Kasan shadow start" },
        { KASAN_SHADOW_END,             "Kasan shadow end" },
 #endif
        { MODULES_VADDR,                "Modules start" },
@@ -42,7 +53,6 @@ static const struct addr_marker address_markers[] = {
        { VMEMMAP_START,                "vmemmap start" },
        { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" },
 #endif
-       { PAGE_OFFSET,                  "Linear mapping" },
        { -1,                           NULL },
 };
 
@@ -376,7 +386,7 @@ static void ptdump_initialize(void)
 static struct ptdump_info kernel_ptdump_info = {
        .mm             = &init_mm,
        .markers        = address_markers,
-       .base_addr      = VA_START,
+       .base_addr      = PAGE_OFFSET,
 };
 
 void ptdump_check_wx(void)
@@ -390,7 +400,7 @@ void ptdump_check_wx(void)
                .check_wx = true,
        };
 
-       walk_pgd(&st, &init_mm, VA_START);
+       walk_pgd(&st, &init_mm, PAGE_OFFSET);
        note_page(&st, 0, 0, 0);
        if (st.wx_pages || st.uxn_pages)
                pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
@@ -401,6 +411,10 @@ void ptdump_check_wx(void)
 
 static int ptdump_init(void)
 {
+       address_markers[PAGE_END_NR].start_address = PAGE_END;
+#ifdef CONFIG_KASAN
+       address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START;
+#endif
        ptdump_initialize();
        ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
        return 0;
index cfd65b6..115d7a0 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/bitfield.h>
 #include <linux/extable.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
@@ -86,8 +87,8 @@ static void mem_abort_decode(unsigned int esr)
        pr_alert("Mem abort info:\n");
 
        pr_alert("  ESR = 0x%08x\n", esr);
-       pr_alert("  Exception class = %s, IL = %u bits\n",
-                esr_get_class_string(esr),
+       pr_alert("  EC = 0x%02lx: %s, IL = %u bits\n",
+                ESR_ELx_EC(esr), esr_get_class_string(esr),
                 (esr & ESR_ELx_IL) ? 32 : 16);
        pr_alert("  SET = %lu, FnV = %lu\n",
                 (esr & ESR_ELx_SET_MASK) >> ESR_ELx_SET_SHIFT,
@@ -109,7 +110,7 @@ static inline bool is_ttbr0_addr(unsigned long addr)
 static inline bool is_ttbr1_addr(unsigned long addr)
 {
        /* TTBR1 addresses may have a tag if KASAN_SW_TAGS is in use */
-       return arch_kasan_reset_tag(addr) >= VA_START;
+       return arch_kasan_reset_tag(addr) >= PAGE_OFFSET;
 }
 
 /*
@@ -138,10 +139,9 @@ static void show_pte(unsigned long addr)
                return;
        }
 
-       pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgdp=%016lx\n",
+       pr_alert("%s pgtable: %luk pages, %llu-bit VAs, pgdp=%016lx\n",
                 mm == &init_mm ? "swapper" : "user", PAGE_SIZE / SZ_1K,
-                mm == &init_mm ? VA_BITS : (int)vabits_user,
-                (unsigned long)virt_to_phys(mm->pgd));
+                vabits_actual, (unsigned long)virt_to_phys(mm->pgd));
        pgdp = pgd_offset(mm, addr);
        pgd = READ_ONCE(*pgdp);
        pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd));
@@ -242,6 +242,34 @@ static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr,
        return false;
 }
 
+static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr,
+                                                       unsigned int esr,
+                                                       struct pt_regs *regs)
+{
+       unsigned long flags;
+       u64 par, dfsc;
+
+       if (ESR_ELx_EC(esr) != ESR_ELx_EC_DABT_CUR ||
+           (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT)
+               return false;
+
+       local_irq_save(flags);
+       asm volatile("at s1e1r, %0" :: "r" (addr));
+       isb();
+       par = read_sysreg(par_el1);
+       local_irq_restore(flags);
+
+       if (!(par & SYS_PAR_EL1_F))
+               return false;
+
+       /*
+        * If we got a different type of fault from the AT instruction,
+        * treat the translation fault as spurious.
+        */
+       dfsc = FIELD_PREP(SYS_PAR_EL1_FST, par);
+       return (dfsc & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT;
+}
+
 static void die_kernel_fault(const char *msg, unsigned long addr,
                             unsigned int esr, struct pt_regs *regs)
 {
@@ -270,6 +298,10 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
        if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
                return;
 
+       if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs),
+           "Ignoring spurious kernel translation fault at virtual address %016lx\n", addr))
+               return;
+
        if (is_el1_permission_fault(addr, esr, regs)) {
                if (esr & ESR_ELx_WNR)
                        msg = "write to read-only memory";
index f3c7952..45c00a5 100644 (file)
 s64 memstart_addr __ro_after_init = -1;
 EXPORT_SYMBOL(memstart_addr);
 
+s64 physvirt_offset __ro_after_init;
+EXPORT_SYMBOL(physvirt_offset);
+
+struct page *vmemmap __ro_after_init;
+EXPORT_SYMBOL(vmemmap);
+
 phys_addr_t arm64_dma_phys_limit __ro_after_init;
 
 #ifdef CONFIG_KEXEC_CORE
@@ -301,7 +307,7 @@ static void __init fdt_enforce_memory_region(void)
 
 void __init arm64_memblock_init(void)
 {
-       const s64 linear_region_size = -(s64)PAGE_OFFSET;
+       const s64 linear_region_size = BIT(vabits_actual - 1);
 
        /* Handle linux,usable-memory-range property */
        fdt_enforce_memory_region();
@@ -309,19 +315,26 @@ void __init arm64_memblock_init(void)
        /* Remove memory above our supported physical address size */
        memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX);
 
-       /*
-        * Ensure that the linear region takes up exactly half of the kernel
-        * virtual address space. This way, we can distinguish a linear address
-        * from a kernel/module/vmalloc address by testing a single bit.
-        */
-       BUILD_BUG_ON(linear_region_size != BIT(VA_BITS - 1));
-
        /*
         * Select a suitable value for the base of physical memory.
         */
        memstart_addr = round_down(memblock_start_of_DRAM(),
                                   ARM64_MEMSTART_ALIGN);
 
+       physvirt_offset = PHYS_OFFSET - PAGE_OFFSET;
+
+       vmemmap = ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT));
+
+       /*
+        * If we are running with a 52-bit kernel VA config on a system that
+        * does not support it, we have to offset our vmemmap and physvirt_offset
+        * s.t. we avoid the 52-bit portion of the direct linear map
+        */
+       if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) {
+               vmemmap += (_PAGE_OFFSET(48) - _PAGE_OFFSET(52)) >> PAGE_SHIFT;
+               physvirt_offset = PHYS_OFFSET - _PAGE_OFFSET(48);
+       }
+
        /*
         * Remove the memory that we will not be able to cover with the
         * linear mapping. Take care not to clip the kernel which may be
@@ -570,8 +583,12 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
+       unsigned long aligned_start, aligned_end;
+
+       aligned_start = __virt_to_phys(start) & PAGE_MASK;
+       aligned_end = PAGE_ALIGN(__virt_to_phys(end));
+       memblock_free(aligned_start, aligned_end - aligned_start);
        free_reserved_area((void *)start, (void *)end, 0, "initrd");
-       memblock_free(__virt_to_phys(start), end - start);
 }
 #endif
 
index fdb595a..9be71be 100644 (file)
@@ -69,7 +69,7 @@ void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
 }
 EXPORT_SYMBOL(__ioremap);
 
-void __iounmap(volatile void __iomem *io_addr)
+void iounmap(volatile void __iomem *io_addr)
 {
        unsigned long addr = (unsigned long)io_addr & PAGE_MASK;
 
@@ -80,7 +80,7 @@ void __iounmap(volatile void __iomem *io_addr)
        if (is_vmalloc_addr((void *)addr))
                vunmap((void *)addr);
 }
-EXPORT_SYMBOL(__iounmap);
+EXPORT_SYMBOL(iounmap);
 
 void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
 {
index 6cf97b9..f87a324 100644 (file)
@@ -156,7 +156,8 @@ asmlinkage void __init kasan_early_init(void)
 {
        BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
                KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
-       BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, PGDIR_SIZE));
+       BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), PGDIR_SIZE));
+       BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), PGDIR_SIZE));
        BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE));
        kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE,
                           true);
@@ -225,10 +226,10 @@ void __init kasan_init(void)
        kasan_map_populate(kimg_shadow_start, kimg_shadow_end,
                           early_pfn_to_nid(virt_to_pfn(lm_alias(_text))));
 
-       kasan_populate_early_shadow((void *)KASAN_SHADOW_START,
-                                   (void *)mod_shadow_start);
+       kasan_populate_early_shadow(kasan_mem_to_shadow((void *)PAGE_END),
+                                  (void *)mod_shadow_start);
        kasan_populate_early_shadow((void *)kimg_shadow_end,
-                                   kasan_mem_to_shadow((void *)PAGE_OFFSET));
+                                  (void *)KASAN_SHADOW_END);
 
        if (kimg_shadow_start > mod_shadow_end)
                kasan_populate_early_shadow((void *)mod_shadow_end,
index 750a69d..53dc6f2 100644 (file)
@@ -40,8 +40,9 @@
 
 u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
 u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
-u64 vabits_user __ro_after_init;
-EXPORT_SYMBOL(vabits_user);
+
+u64 __section(".mmuoff.data.write") vabits_actual;
+EXPORT_SYMBOL(vabits_actual);
 
 u64 kimage_voffset __ro_after_init;
 EXPORT_SYMBOL(kimage_voffset);
@@ -398,7 +399,7 @@ static phys_addr_t pgd_pgtable_alloc(int shift)
 static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
                                  phys_addr_t size, pgprot_t prot)
 {
-       if (virt < VMALLOC_START) {
+       if ((virt >= PAGE_END) && (virt < VMALLOC_START)) {
                pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
                        &phys, virt);
                return;
@@ -425,7 +426,7 @@ void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
 static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
                                phys_addr_t size, pgprot_t prot)
 {
-       if (virt < VMALLOC_START) {
+       if ((virt >= PAGE_END) && (virt < VMALLOC_START)) {
                pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
                        &phys, virt);
                return;
@@ -646,6 +647,8 @@ static void __init map_kernel(pgd_t *pgdp)
                set_pgd(pgd_offset_raw(pgdp, FIXADDR_START),
                        READ_ONCE(*pgd_offset_k(FIXADDR_START)));
        } else if (CONFIG_PGTABLE_LEVELS > 3) {
+               pgd_t *bm_pgdp;
+               pud_t *bm_pudp;
                /*
                 * The fixmap shares its top level pgd entry with the kernel
                 * mapping. This can really only occur when we are running
@@ -653,9 +656,9 @@ static void __init map_kernel(pgd_t *pgdp)
                 * entry instead.
                 */
                BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
-               pud_populate(&init_mm,
-                            pud_set_fixmap_offset(pgdp, FIXADDR_START),
-                            lm_alias(bm_pmd));
+               bm_pgdp = pgd_offset_raw(pgdp, FIXADDR_START);
+               bm_pudp = pud_set_fixmap_offset(bm_pgdp, FIXADDR_START);
+               pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd));
                pud_clear_fixmap();
        } else {
                BUG();
@@ -876,7 +879,7 @@ void __set_fixmap(enum fixed_addresses idx,
        }
 }
 
-void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
+void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
 {
        const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
        int offset;
@@ -929,19 +932,6 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
        return dt_virt;
 }
 
-void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
-{
-       void *dt_virt;
-       int size;
-
-       dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
-       if (!dt_virt)
-               return NULL;
-
-       memblock_reserve(dt_phys, size);
-       return dt_virt;
-}
-
 int __init arch_ioremap_p4d_supported(void)
 {
        return 0;
index 4f241cc..4decf16 100644 (file)
@@ -29,7 +29,7 @@ static __init int numa_parse_early_param(char *opt)
 {
        if (!opt)
                return -EINVAL;
-       if (!strncmp(opt, "off", 3))
+       if (str_has_prefix(opt, "off"))
                numa_off = true;
 
        return 0;
index 03c53f1..9ce7bd9 100644 (file)
@@ -128,7 +128,6 @@ int set_memory_nx(unsigned long addr, int numpages)
                                        __pgprot(PTE_PXN),
                                        __pgprot(0));
 }
-EXPORT_SYMBOL_GPL(set_memory_nx);
 
 int set_memory_x(unsigned long addr, int numpages)
 {
@@ -136,7 +135,6 @@ int set_memory_x(unsigned long addr, int numpages)
                                        __pgprot(0),
                                        __pgprot(PTE_PXN));
 }
-EXPORT_SYMBOL_GPL(set_memory_x);
 
 int set_memory_valid(unsigned long addr, int numpages, int enable)
 {
index 7dbf2be..a1e0592 100644 (file)
@@ -168,7 +168,7 @@ ENDPROC(cpu_do_switch_mm)
 .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
        adrp    \tmp1, empty_zero_page
        phys_to_ttbr \tmp2, \tmp1
-       offset_ttbr1 \tmp2
+       offset_ttbr1 \tmp2, \tmp1
        msr     ttbr1_el1, \tmp2
        isb
        tlbi    vmalle1
@@ -187,7 +187,7 @@ ENTRY(idmap_cpu_replace_ttbr1)
 
        __idmap_cpu_set_reserved_ttbr1 x1, x3
 
-       offset_ttbr1 x0
+       offset_ttbr1 x0, x3
        msr     ttbr1_el1, x0
        isb
 
@@ -286,6 +286,15 @@ skip_pgd:
        msr     sctlr_el1, x18
        isb
 
+       /*
+        * Invalidate the local I-cache so that any instructions fetched
+        * speculatively from the PoC are discarded, since they may have
+        * been dynamically patched at the PoU.
+        */
+       ic      iallu
+       dsb     nsh
+       isb
+
        /* Set the flag to zero to indicate that we're all done */
        str     wzr, [flag_ptr]
        ret
@@ -362,7 +371,7 @@ __idmap_kpti_secondary:
        cbnz    w18, 1b
 
        /* All done, act like nothing happened */
-       offset_ttbr1 swapper_ttb
+       offset_ttbr1 swapper_ttb, x18
        msr     ttbr1_el1, swapper_ttb
        isb
        ret
@@ -438,10 +447,11 @@ ENTRY(__cpu_setup)
                        TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS
        tcr_clear_errata_bits x10, x9, x5
 
-#ifdef CONFIG_ARM64_USER_VA_BITS_52
-       ldr_l           x9, vabits_user
+#ifdef CONFIG_ARM64_VA_BITS_52
+       ldr_l           x9, vabits_actual
        sub             x9, xzr, x9
        add             x9, x9, #64
+       tcr_set_t1sz    x10, x9
 #else
        ldr_l           x9, idmap_t0sz
 #endif
index 7468d8e..13d49c2 100644 (file)
@@ -10,12 +10,14 @@ config IA64
        bool
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
-       select ACPI if (!IA64_HP_SIM)
-       select ARCH_SUPPORTS_ACPI if (!IA64_HP_SIM)
+       select ACPI
+       select ACPI_NUMA if NUMA
+       select ARCH_SUPPORTS_ACPI
        select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
-       select FORCE_PCI if (!IA64_HP_SIM)
+       select FORCE_PCI
        select PCI_DOMAINS if PCI
+       select PCI_MSI
        select PCI_SYSCALL if PCI
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_EXIT_THREAD
@@ -30,8 +32,8 @@ config IA64
        select HAVE_ARCH_TRACEHOOK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_VIRT_CPU_ACCOUNTING
-       select ARCH_HAS_DMA_COHERENT_TO_PFN if SWIOTLB
-       select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB
+       select ARCH_HAS_DMA_COHERENT_TO_PFN
+       select ARCH_HAS_SYNC_DMA_FOR_CPU
        select VIRT_TO_BUS
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
@@ -45,6 +47,7 @@ config IA64
        select ARCH_THREAD_STACK_ALLOCATOR
        select ARCH_CLOCKSOURCE_DATA
        select GENERIC_TIME_VSYSCALL
+       select SWIOTLB
        select SYSCTL_ARCH_UNALIGN_NO_WARN
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
@@ -52,6 +55,7 @@ config IA64
        select HAVE_ARCH_AUDITSYSCALL
        select NEED_DMA_MAP_STATE
        select NEED_SG_DMA_LENGTH
+       select NUMA if !FLATMEM
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -66,7 +70,6 @@ config 64BIT
 
 config ZONE_DMA32
        def_bool y
-       depends on !IA64_SGI_SN2
 
 config QUICKLIST
        bool
@@ -120,87 +123,6 @@ config AUDIT_ARCH
        bool
        default y
 
-choice
-       prompt "System type"
-       default IA64_GENERIC
-
-config IA64_GENERIC
-       bool "generic"
-       select NUMA
-       select ACPI_NUMA
-       select SWIOTLB
-       select PCI_MSI
-       help
-         This selects the system type of your hardware.  A "generic" kernel
-         will run on any supported IA-64 system.  However, if you configure
-         a kernel for your specific system, it will be faster and smaller.
-
-         generic               For any supported IA-64 system
-         DIG-compliant         For DIG ("Developer's Interface Guide") compliant systems
-         DIG+Intel+IOMMU       For DIG systems with Intel IOMMU
-         HP-zx1/sx1000         For HP systems
-         HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices.
-         SGI-SN2               For SGI Altix systems
-         SGI-UV                For SGI UV systems
-         Ski-simulator         For the HP simulator <http://www.hpl.hp.com/research/linux/ski/>
-
-         If you don't know what to do, choose "generic".
-
-config IA64_DIG
-       bool "DIG-compliant"
-       select SWIOTLB
-
-config IA64_DIG_VTD
-       bool "DIG+Intel+IOMMU"
-       select INTEL_IOMMU
-       select PCI_MSI
-
-config IA64_HP_ZX1
-       bool "HP-zx1/sx1000"
-       help
-         Build a kernel that runs on HP zx1 and sx1000 systems.  This adds
-         support for the HP I/O MMU.
-
-config IA64_HP_ZX1_SWIOTLB
-       bool "HP-zx1/sx1000 with software I/O TLB"
-       select SWIOTLB
-       help
-         Build a kernel that runs on HP zx1 and sx1000 systems even when they
-         have broken PCI devices which cannot DMA to full 32 bits.  Apart
-         from support for the HP I/O MMU, this includes support for the software
-         I/O TLB, which allows supporting the broken devices at the expense of
-         wasting some kernel memory (about 2MB by default).
-
-config IA64_SGI_SN2
-       bool "SGI-SN2"
-       select NUMA
-       select ACPI_NUMA
-       help
-         Selecting this option will optimize the kernel for use on sn2 based
-         systems, but the resulting kernel binary will not run on other
-         types of ia64 systems.  If you have an SGI Altix system, it's safe
-         to select this option.  If in doubt, select ia64 generic support
-         instead.
-
-config IA64_SGI_UV
-       bool "SGI-UV"
-       select NUMA
-       select ACPI_NUMA
-       select SWIOTLB
-       help
-         Selecting this option will optimize the kernel for use on UV based
-         systems, but the resulting kernel binary will not run on other
-         types of ia64 systems.  If you have an SGI UV system, it's safe
-         to select this option.  If in doubt, select ia64 generic support
-         instead.
-
-config IA64_HP_SIM
-       bool "Ski-simulator"
-       select SWIOTLB
-       depends on !PM
-
-endchoice
-
 choice
        prompt "Processor type"
        default ITANIUM
@@ -252,14 +174,7 @@ config IA64_PAGE_SIZE_64KB
 
 endchoice
 
-if IA64_HP_SIM
-config HZ
-       default 32
-endif
-
-if !IA64_HP_SIM
 source "kernel/Kconfig.hz"
-endif
 
 config IA64_BRL_EMU
        bool
@@ -272,17 +187,26 @@ config IA64_L1_CACHE_SHIFT
        default "7" if MCKINLEY
        default "6" if ITANIUM
 
+config IA64_SGI_UV
+       bool "SGI-UV support"
+       help
+         Selecting this option will add specific support for running on SGI
+         UV based systems.  If you have an SGI UV system or are building a
+         distro kernel, select this option.
+
+config IA64_HP_SBA_IOMMU
+       bool "HP SBA IOMMU support"
+       default y
+       help
+         Say Y here to add support for the SBA IOMMU found on HP zx1 and
+         sx1000 systems.  If you're unsure, answer Y.
+
 config IA64_CYCLONE
        bool "Cyclone (EXA) Time Source support"
        help
          Say Y here to enable support for IBM EXA Cyclone time source.
          If you're unsure, answer N.
 
-config IOSAPIC
-       bool
-       depends on !IA64_HP_SIM
-       default y
-
 config FORCE_MAX_ZONEORDER
        int "MAX_ORDER (11 - 17)"  if !HUGETLB_PAGE
        range 11 17  if !HUGETLB_PAGE
@@ -381,14 +305,12 @@ config ARCH_SPARSEMEM_ENABLE
        select SPARSEMEM_VMEMMAP_ENABLE
 
 config ARCH_DISCONTIGMEM_DEFAULT
-       def_bool y if (IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB)
+       def_bool y
        depends on ARCH_DISCONTIGMEM_ENABLE
 
 config NUMA
        bool "NUMA support"
-       depends on !IA64_HP_SIM && !FLATMEM
-       default y if IA64_SGI_SN2
-       select ACPI_NUMA if ACPI
+       depends on !FLATMEM
        help
          Say Y to compile the kernel to support NUMA (Non-Uniform Memory
          Access).  This option is for configuring high-end multiprocessor
@@ -409,7 +331,7 @@ config NODES_SHIFT
 config VIRTUAL_MEM_MAP
        bool "Virtual mem map"
        depends on !SPARSEMEM
-       default y if !IA64_HP_SIM
+       default y
        help
          Say Y to compile the kernel with support for a virtual mem map.
          This code also only takes effect if a memory hole of greater than
@@ -472,9 +394,6 @@ config IA64_MC_ERR_INJECT
 
          If you're unsure, do not select this option.
 
-config SGI_SN
-       def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
-
 config IA64_ESI
        bool "ESI (Extensible SAL Interface) support"
        help
@@ -493,11 +412,9 @@ config IA64_HP_AML_NFW
          the "force" module parameter, e.g., with the "aml_nfw.force"
          kernel command line option.
 
-source "drivers/sn/Kconfig"
-
 config KEXEC
        bool "kexec system call"
-       depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
+       depends on !SMP || HOTPLUG_CPU
        select KEXEC_CORE
        help
          kexec is a system call that implements the ability to shutdown your
@@ -515,7 +432,7 @@ config KEXEC
 
 config CRASH_DUMP
          bool "kernel crash dumps"
-         depends on IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
+         depends on IA64_MCA_RECOVERY && (!SMP || HOTPLUG_CPU)
          help
            Generate crash dump after being started by kexec.
 
@@ -537,8 +454,6 @@ endif
 
 endmenu
 
-source "arch/ia64/hp/sim/Kconfig"
-
 config MSPEC
        tristate "Memory special operations driver"
        depends on IA64
index 1371efc..40ca23b 100644 (file)
@@ -14,7 +14,7 @@ config IA64_GRANULE_16MB
 
 config IA64_GRANULE_64MB
        bool "64MB"
-       depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_SGI_SN2)
+       depends on BROKEN
 
 endchoice
 
index 171290f..e0bb2b6 100644 (file)
@@ -39,29 +39,23 @@ $(error Sorry, you need a newer version of the assember, one that is built from
                ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz)
 endif
 
+quiet_cmd_gzip = GZIP    $@
+cmd_gzip = cat $(real-prereqs) | gzip -n -f -9 > $@
+
+quiet_cmd_objcopy = OBJCOPY $@
+cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
+
 KBUILD_CFLAGS += $(cflags-y)
 head-y := arch/ia64/kernel/head.o
 
 libs-y                         += arch/ia64/lib/
 core-y                         += arch/ia64/kernel/ arch/ia64/mm/
-core-$(CONFIG_IA64_DIG)        += arch/ia64/dig/
-core-$(CONFIG_IA64_DIG_VTD)    += arch/ia64/dig/
-core-$(CONFIG_IA64_GENERIC)    += arch/ia64/dig/
-core-$(CONFIG_IA64_HP_ZX1)     += arch/ia64/dig/
-core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
-core-$(CONFIG_IA64_SGI_SN2)    += arch/ia64/sn/
 core-$(CONFIG_IA64_SGI_UV)     += arch/ia64/uv/
 
-drivers-$(CONFIG_PCI)          += arch/ia64/pci/
-drivers-$(CONFIG_IA64_HP_SIM)  += arch/ia64/hp/sim/
-drivers-$(CONFIG_IA64_HP_ZX1)  += arch/ia64/hp/common/ arch/ia64/hp/zx1/
-drivers-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
-drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/ arch/ia64/uv/
+drivers-y                      += arch/ia64/pci/ arch/ia64/hp/common/
 drivers-$(CONFIG_OPROFILE)     += arch/ia64/oprofile/
 
-boot := arch/ia64/hp/sim/boot
-
-PHONY += boot compressed check
+PHONY += compressed check
 
 all: compressed unwcheck
 
@@ -69,22 +63,21 @@ compressed: vmlinux.gz
 
 vmlinuz: vmlinux.gz
 
-vmlinux.gz: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) $@
+vmlinux.gz: vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
 
 unwcheck: vmlinux
        -$(Q)READELF=$(READELF) $(PYTHON) $(srctree)/arch/ia64/scripts/unwcheck.py $<
 
 archclean:
-       $(Q)$(MAKE) $(clean)=$(boot)
 
 archheaders:
        $(Q)$(MAKE) $(build)=arch/ia64/kernel/syscalls all
 
-CLEAN_FILES += vmlinux.gz bootloader
-
-boot:  lib/lib.a vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) $@
+CLEAN_FILES += vmlinux.gz
 
 install: vmlinux.gz
        sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
@@ -92,7 +85,6 @@ install: vmlinux.gz
 define archhelp
   echo '* compressed   - Build compressed kernel image'
   echo '  install      - Install compressed kernel image'
-  echo '  boot         - Build vmlinux and bootloader for Ski simulator'
   echo '* unwcheck     - Check vmlinux for invalid unwind info'
 endef
 
index b6bda18..b630bd7 100644 (file)
@@ -7,7 +7,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_SGI_PARTITION=y
-CONFIG_IA64_DIG=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_PREEMPT=y
index 81f686d..661d90b 100644 (file)
@@ -44,14 +44,12 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_SGI_IOC4=y
 CONFIG_SGI_XP=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_GENERIC=y
 CONFIG_BLK_DEV_CMD64X=y
 CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_SGIIOC4=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=m
@@ -90,16 +88,11 @@ CONFIG_IGB=y
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_GAMEPORT=m
 CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_SGI_SNSC=y
-CONFIG_SGI_TIOCX=y
-CONFIG_SGI_MBCS=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=6
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_SGI_L1_CONSOLE=y
-CONFIG_SERIAL_SGI_IOC4=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
 CONFIG_RAW_DRIVER=m
@@ -107,7 +100,6 @@ CONFIG_HPET=y
 CONFIG_AGP=m
 CONFIG_AGP_I460=m
 CONFIG_AGP_HP_ZX1=m
-CONFIG_AGP_SGI_TIOCA=m
 CONFIG_DRM=m
 CONFIG_DRM_TDFX=m
 CONFIG_DRM_R128=m
index 5b4fcdd..7844e6a 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-CONFIG_SGI_IOC3=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=m
 CONFIG_ACPI_BUTTON=m
@@ -37,14 +36,12 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_SGI_IOC4=y
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_IDE_GENERIC=y
 CONFIG_BLK_DEV_GENERIC=y
 CONFIG_BLK_DEV_CMD64X=y
 CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_SGIIOC4=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
@@ -79,17 +76,11 @@ CONFIG_E1000=y
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_GAMEPORT=m
 CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_SGI_SNSC=y
-CONFIG_SGI_TIOCX=y
-CONFIG_SGI_MBCS=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=6
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_SGI_L1_CONSOLE=y
-CONFIG_SERIAL_SGI_IOC4=y
-CONFIG_SERIAL_SGI_IOC3=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
 CONFIG_RAW_DRIVER=m
@@ -97,7 +88,6 @@ CONFIG_HPET=y
 CONFIG_AGP=m
 CONFIG_AGP_I460=m
 CONFIG_AGP_HP_ZX1=m
-CONFIG_AGP_SGI_TIOCA=m
 CONFIG_DRM=m
 CONFIG_DRM_TDFX=m
 CONFIG_DRM_R128=m
diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig
deleted file mode 100644 (file)
index f0f69fd..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_IA64_HP_SIM=y
-CONFIG_MCKINLEY=y
-CONFIG_IA64_PAGE_SIZE_64KB=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=64
-CONFIG_PREEMPT=y
-CONFIG_IA64_PALINFO=m
-CONFIG_EFI_VARS=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IPV6 is not set
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_EFI_RTC=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_HP_SIMETH=y
-CONFIG_HP_SIMSERIAL=y
-CONFIG_HP_SIMSERIAL_CONSOLE=y
-CONFIG_HP_SIMSCSI=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_PROC_KCORE=y
-CONFIG_HUGETLBFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
index 192ed15..1d6e2a0 100644 (file)
@@ -12,7 +12,6 @@ CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_SGI_PARTITION=y
-CONFIG_IA64_DIG=y
 CONFIG_MCKINLEY=y
 CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_IA64_CYCLONE=y
index b504c8e..8c92e09 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_IA64_HP_ZX1=y
 CONFIG_MCKINLEY=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
diff --git a/arch/ia64/dig/Makefile b/arch/ia64/dig/Makefile
deleted file mode 100644 (file)
index e7f8308..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# ia64/platform/dig/Makefile
-#
-# Copyright (C) 1999 Silicon Graphics, Inc.
-# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
-#
-
-obj-y := setup.o
-ifeq ($(CONFIG_INTEL_IOMMU), y)
-obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o
-else
-obj-$(CONFIG_IA64_GENERIC) += machvec.o
-endif
-
diff --git a/arch/ia64/dig/machvec.c b/arch/ia64/dig/machvec.c
deleted file mode 100644 (file)
index 0c55bda..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MACHVEC_PLATFORM_NAME          dig
-#define MACHVEC_PLATFORM_HEADER                <asm/machvec_dig.h>
-#include <asm/machvec_init.h>
diff --git a/arch/ia64/dig/machvec_vtd.c b/arch/ia64/dig/machvec_vtd.c
deleted file mode 100644 (file)
index 7cd3eb4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MACHVEC_PLATFORM_NAME          dig_vtd
-#define MACHVEC_PLATFORM_HEADER                <asm/machvec_dig_vtd.h>
-#include <asm/machvec_init.h>
diff --git a/arch/ia64/dig/setup.c b/arch/ia64/dig/setup.c
deleted file mode 100644 (file)
index cc14fdc..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Platform dependent support for DIG64 platforms.
- *
- * Copyright (C) 1999 Intel Corp.
- * Copyright (C) 1999, 2001 Hewlett-Packard Co
- * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/kdev_t.h>
-#include <linux/string.h>
-#include <linux/screen_info.h>
-#include <linux/console.h>
-#include <linux/timex.h>
-#include <linux/sched.h>
-#include <linux/root_dev.h>
-
-#include <asm/io.h>
-#include <asm/machvec.h>
-#include <asm/setup.h>
-
-void __init
-dig_setup (char **cmdline_p)
-{
-       unsigned int orig_x, orig_y, num_cols, num_rows, font_height;
-
-       /*
-        * Default to /dev/sda2.  This assumes that the EFI partition
-        * is physical disk 1 partition 1 and the Linux root disk is
-        * physical disk 1 partition 2.
-        */
-       ROOT_DEV = Root_SDA2;           /* default to second partition on first drive */
-
-#ifdef CONFIG_SMP
-       init_smp_config();
-#endif
-
-       memset(&screen_info, 0, sizeof(screen_info));
-
-       if (!ia64_boot_param->console_info.num_rows
-           || !ia64_boot_param->console_info.num_cols)
-       {
-               printk(KERN_WARNING "dig_setup: warning: invalid screen-info, guessing 80x25\n");
-               orig_x = 0;
-               orig_y = 0;
-               num_cols = 80;
-               num_rows = 25;
-               font_height = 16;
-       } else {
-               orig_x = ia64_boot_param->console_info.orig_x;
-               orig_y = ia64_boot_param->console_info.orig_y;
-               num_cols = ia64_boot_param->console_info.num_cols;
-               num_rows = ia64_boot_param->console_info.num_rows;
-               font_height = 400 / num_rows;
-       }
-
-       screen_info.orig_x = orig_x;
-       screen_info.orig_y = orig_y;
-       screen_info.orig_video_cols  = num_cols;
-       screen_info.orig_video_lines = num_rows;
-       screen_info.orig_video_points = font_height;
-       screen_info.orig_video_mode = 3;        /* XXX fake */
-       screen_info.orig_video_isVGA = 1;       /* XXX fake */
-       screen_info.orig_video_ega_bx = 3;      /* XXX fake */
-}
index 6026308..11a56ed 100644 (file)
@@ -6,7 +6,5 @@
 # Copyright (C) Alex Williamson (alex_williamson@hp.com)
 #
 
-obj-y := sba_iommu.o
-obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += hwsw_iommu.o
-obj-$(CONFIG_IA64_GENERIC) += hwsw_iommu.o
+obj-$(CONFIG_IA64_HP_SBA_IOMMU) += sba_iommu.o
 obj-$(CONFIG_IA64_HP_AML_NFW) += aml_nfw.o
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
deleted file mode 100644 (file)
index 8840ed9..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
- *   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * This is a pseudo I/O MMU which dispatches to the hardware I/O MMU
- * whenever possible.  We assume that the hardware I/O MMU requires
- * full 32-bit addressability, as is the case, e.g., for HP zx1-based
- * systems (there, the I/O MMU window is mapped at 3-4GB).  If a
- * device doesn't provide full 32-bit addressability, we fall back on
- * the sw I/O TLB.  This is good enough to let us support broken
- * hardware such as soundcards which have a DMA engine that can
- * address only 28 bits.
- */
-
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/swiotlb.h>
-#include <linux/export.h>
-#include <asm/machvec.h>
-
-extern const struct dma_map_ops sba_dma_ops;
-
-/* swiotlb declarations & definitions: */
-extern int swiotlb_late_init_with_default_size (size_t size);
-
-/*
- * Note: we need to make the determination of whether or not to use
- * the sw I/O TLB based purely on the device structure.  Anything else
- * would be unreliable or would be too intrusive.
- */
-static inline int use_swiotlb(struct device *dev)
-{
-       return dev && dev->dma_mask &&
-               !sba_dma_ops.dma_supported(dev, *dev->dma_mask);
-}
-
-const struct dma_map_ops *hwsw_dma_get_ops(struct device *dev)
-{
-       if (use_swiotlb(dev))
-               return NULL;
-       return &sba_dma_ops;
-}
-EXPORT_SYMBOL(hwsw_dma_get_ops);
-
-void __init
-hwsw_init (void)
-{
-       /* default to a smallish 2MB sw I/O TLB */
-       if (swiotlb_late_init_with_default_size (2 * (1<<20)) != 0) {
-#ifdef CONFIG_IA64_GENERIC
-               /* Better to have normal DMA than panic */
-               printk(KERN_WARNING "%s: Failed to initialize software I/O TLB,"
-                      " reverting to hpzx1 platform vector\n", __func__);
-               machvec_init("hpzx1");
-#else
-               panic("Unable to initialize software I/O TLB services");
-#endif
-       }
-}
index 3d24cc4..a7eff5e 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/iommu-helper.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
+#include <linux/swiotlb.h>
 
 #include <asm/delay.h>         /* ia64_get_itc() */
 #include <asm/io.h>
@@ -43,8 +44,6 @@
 
 #include <asm/acpi-ext.h>
 
-extern int swiotlb_late_init_with_default_size (size_t size);
-
 #define PFX "IOC: "
 
 /*
@@ -251,12 +250,8 @@ static SBA_INLINE void sba_free_range(struct ioc *, dma_addr_t, size_t);
 static u64 prefetch_spill_page;
 #endif
 
-#ifdef CONFIG_PCI
-# define GET_IOC(dev)  ((dev_is_pci(dev))                                              \
+#define GET_IOC(dev)   ((dev_is_pci(dev))                                              \
                         ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL)
-#else
-# define GET_IOC(dev)  NULL
-#endif
 
 /*
 ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
@@ -1741,9 +1736,7 @@ ioc_sac_init(struct ioc *ioc)
        controller->iommu = ioc;
        sac->sysdata = controller;
        sac->dma_mask = 0xFFFFFFFFUL;
-#ifdef CONFIG_PCI
        sac->dev.bus = &pci_bus_type;
-#endif
        ioc->sac_only_dev = sac;
 }
 
@@ -2062,27 +2055,33 @@ static int __init acpi_sba_ioc_init_acpi(void)
 /* This has to run before acpi_scan_init(). */
 arch_initcall(acpi_sba_ioc_init_acpi);
 
+static int sba_dma_supported (struct device *dev, u64 mask)
+{
+       /* make sure it's at least 32bit capable */
+       return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);
+}
+
+static const struct dma_map_ops sba_dma_ops = {
+       .alloc                  = sba_alloc_coherent,
+       .free                   = sba_free_coherent,
+       .map_page               = sba_map_page,
+       .unmap_page             = sba_unmap_page,
+       .map_sg                 = sba_map_sg_attrs,
+       .unmap_sg               = sba_unmap_sg_attrs,
+       .dma_supported          = sba_dma_supported,
+};
+
 static int __init
 sba_init(void)
 {
-       if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb"))
-               return 0;
-
-#if defined(CONFIG_IA64_GENERIC)
-       /* If we are booting a kdump kernel, the sba_iommu will
-        * cause devices that were not shutdown properly to MCA
-        * as soon as they are turned back on.  Our only option for
-        * a successful kdump kernel boot is to use the swiotlb.
+       /*
+        * If we are booting a kdump kernel, the sba_iommu will cause devices
+        * that were not shutdown properly to MCA as soon as they are turned
+        * back on.  Our only option for a successful kdump kernel boot is to
+        * use swiotlb.
         */
-       if (is_kdump_kernel()) {
-               dma_ops = NULL;
-               if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
-                       panic("Unable to initialize software I/O TLB:"
-                                 " Try machvec=dig boot option");
-               machvec_init("dig");
+       if (is_kdump_kernel())
                return 0;
-       }
-#endif
 
        /*
         * ioc_found should be populated by the acpi_sba_ioc_handler's .attach()
@@ -2091,43 +2090,18 @@ sba_init(void)
        while (ioc_found)
                acpi_sba_ioc_add(ioc_found);
 
-       if (!ioc_list) {
-#ifdef CONFIG_IA64_GENERIC
-               /*
-                * If we didn't find something sba_iommu can claim, we
-                * need to setup the swiotlb and switch to the dig machvec.
-                */
-               dma_ops = NULL;
-               if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
-                       panic("Unable to find SBA IOMMU or initialize "
-                             "software I/O TLB: Try machvec=dig boot option");
-               machvec_init("dig");
-#else
-               panic("Unable to find SBA IOMMU: Try a generic or DIG kernel");
-#endif
+       if (!ioc_list)
                return 0;
-       }
 
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_HP_ZX1_SWIOTLB)
-       /*
-        * hpzx1_swiotlb needs to have a fairly small swiotlb bounce
-        * buffer setup to support devices with smaller DMA masks than
-        * sba_iommu can handle.
-        */
-       if (ia64_platform_is("hpzx1_swiotlb")) {
-               extern void hwsw_init(void);
-
-               hwsw_init();
-       }
-#endif
-
-#ifdef CONFIG_PCI
        {
                struct pci_bus *b = NULL;
                while ((b = pci_find_next_bus(b)) != NULL)
                        sba_connect_bus(b);
        }
-#endif
+
+       /* no need for swiotlb with the iommu */
+       swiotlb_exit();
+       dma_ops = &sba_dma_ops;
 
 #ifdef CONFIG_PROC_FS
        ioc_proc_init();
@@ -2144,12 +2118,6 @@ nosbagart(char *str)
        return 1;
 }
 
-static int sba_dma_supported (struct device *dev, u64 mask)
-{
-       /* make sure it's at least 32bit capable */
-       return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);
-}
-
 __setup("nosbagart", nosbagart);
 
 static int __init
@@ -2174,18 +2142,3 @@ sba_page_override(char *str)
 }
 
 __setup("sbapagesize=",sba_page_override);
-
-const struct dma_map_ops sba_dma_ops = {
-       .alloc                  = sba_alloc_coherent,
-       .free                   = sba_free_coherent,
-       .map_page               = sba_map_page,
-       .unmap_page             = sba_unmap_page,
-       .map_sg                 = sba_map_sg_attrs,
-       .unmap_sg               = sba_unmap_sg_attrs,
-       .dma_supported          = sba_dma_supported,
-};
-
-void sba_dma_init(void)
-{
-       dma_ops = &sba_dma_ops;
-}
diff --git a/arch/ia64/hp/sim/Kconfig b/arch/ia64/hp/sim/Kconfig
deleted file mode 100644 (file)
index 56fb4f1..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-menu "HP Simulator drivers"
-       depends on IA64_HP_SIM || IA64_GENERIC
-
-config HP_SIMETH
-       bool "Simulated Ethernet "
-       depends on NET
-
-config HP_SIMSERIAL
-       bool "Simulated serial driver support"
-       depends on TTY
-
-config HP_SIMSERIAL_CONSOLE
-       bool "Console for HP simulator"
-       depends on HP_SIMSERIAL
-
-config HP_SIMSCSI
-       bool "Simulated SCSI disk"
-       depends on SCSI=y
-
-endmenu
-
diff --git a/arch/ia64/hp/sim/Makefile b/arch/ia64/hp/sim/Makefile
deleted file mode 100644 (file)
index 0224a13..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# ia64/platform/hp/sim/Makefile
-#
-# Copyright (C) 2002 Hewlett-Packard Co.
-#      David Mosberger-Tang <davidm@hpl.hp.com>
-# Copyright (C) 1999 Silicon Graphics, Inc.
-# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
-#
-
-obj-y := hpsim_irq.o hpsim_setup.o hpsim.o
-obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o
-
-obj-$(CONFIG_HP_SIMETH)        += simeth.o
-obj-$(CONFIG_HP_SIMSERIAL) += simserial.o
-obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o
-obj-$(CONFIG_HP_SIMSCSI) += simscsi.o
diff --git a/arch/ia64/hp/sim/boot/Makefile b/arch/ia64/hp/sim/boot/Makefile
deleted file mode 100644 (file)
index df6e996..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# ia64/boot/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1998, 2003 by David Mosberger-Tang <davidm@hpl.hp.com>
-#
-
-targets-$(CONFIG_IA64_HP_SIM)  += bootloader
-targets := vmlinux.bin vmlinux.gz $(targets-y)
-
-quiet_cmd_cptotop = LN      $@
-      cmd_cptotop = ln -f $< $@
-
-vmlinux.gz: $(obj)/vmlinux.gz $(addprefix $(obj)/,$(targets-y))
-       $(call cmd,cptotop)
-       @echo '  Kernel: $@ is ready'
-
-boot: bootloader
-
-bootloader: $(obj)/bootloader
-       $(call cmd,cptotop)
-
-$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
-       $(call if_changed,gzip)
-
-$(obj)/vmlinux.bin: vmlinux FORCE
-       $(call if_changed,objcopy)
-
-
-LDFLAGS_bootloader = -static -T
-
-$(obj)/bootloader: $(src)/bootloader.lds $(obj)/bootloader.o $(obj)/boot_head.o $(obj)/fw-emu.o \
-                   lib/lib.a arch/ia64/lib/lib.a FORCE
-       $(call if_changed,ld)
diff --git a/arch/ia64/hp/sim/boot/boot_head.S b/arch/ia64/hp/sim/boot/boot_head.S
deleted file mode 100644 (file)
index a7d178f..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <asm/asmmacro.h>
-#include <asm/pal.h>
-
-       .bss
-       .align 16
-stack_mem:
-       .skip 16834
-
-       .text
-
-/* This needs to be defined because lib/string.c:strlcat() calls it in case of error... */
-GLOBAL_ENTRY(printk)
-       break 0
-END(printk)
-
-GLOBAL_ENTRY(_start)
-       .prologue
-       .save rp, r0
-       .body
-       movl gp = __gp
-       movl sp = stack_mem+16384-16
-       bsw.1
-       br.call.sptk.many rp=start_bootloader
-0:     nop 0             /* dummy nop to make unwinding work */
-END(_start)
-
-/*
- * Set a break point on this function so that symbols are available to set breakpoints in
- * the kernel being debugged.
- */
-GLOBAL_ENTRY(debug_break)
-       br.ret.sptk.many b0
-END(debug_break)
-
-GLOBAL_ENTRY(ssc)
-       .regstk 5,0,0,0
-       mov r15=in4
-       break 0x80001
-       br.ret.sptk.many b0
-END(ssc)
-
-GLOBAL_ENTRY(jmp_to_kernel)
-       .regstk 2,0,0,0
-       mov r28=in0
-       mov b7=in1
-       br.sptk.few b7
-END(jmp_to_kernel)
-
-/*
- * r28 contains the index of the PAL function
- * r29--31 the args
- * Return values in ret0--3 (r8--11)
- */
-GLOBAL_ENTRY(pal_emulator_static)
-       mov r8=-1
-       mov r9=256
-       ;;
-       cmp.gtu p6,p7=r9,r28            /* r28 <= 255? */
-(p6)   br.cond.sptk.few static
-       ;;
-       mov r9=512
-       ;;
-       cmp.gtu p6,p7=r9,r28
-(p6)   br.cond.sptk.few stacked
-       ;;
-static:        cmp.eq p6,p7=PAL_PTCE_INFO,r28
-(p7)   br.cond.sptk.few 1f
-       ;;
-       mov r8=0                        /* status = 0 */
-       movl r9=0x100000000             /* tc.base */
-       movl r10=0x0000000200000003     /* count[0], count[1] */
-       movl r11=0x1000000000002000     /* stride[0], stride[1] */
-       br.cond.sptk.few rp
-1:     cmp.eq p6,p7=PAL_FREQ_RATIOS,r28
-(p7)   br.cond.sptk.few 1f
-       mov r8=0                        /* status = 0 */
-       movl r9 =0x100000064            /* proc_ratio (1/100) */
-       movl r10=0x100000100            /* bus_ratio<<32 (1/256) */
-       movl r11=0x100000064            /* itc_ratio<<32 (1/100) */
-       ;;
-1:     cmp.eq p6,p7=PAL_RSE_INFO,r28
-(p7)   br.cond.sptk.few 1f
-       mov r8=0                        /* status = 0 */
-       mov r9=96                       /* num phys stacked */
-       mov r10=0                       /* hints */
-       mov r11=0
-       br.cond.sptk.few rp
-1:     cmp.eq p6,p7=PAL_CACHE_FLUSH,r28                /* PAL_CACHE_FLUSH */
-(p7)   br.cond.sptk.few 1f
-       mov r9=ar.lc
-       movl r8=524288                  /* flush 512k million cache lines (16MB) */
-       ;;
-       mov ar.lc=r8
-       movl r8=0xe000000000000000
-       ;;
-.loop: fc r8
-       add r8=32,r8
-       br.cloop.sptk.few .loop
-       sync.i
-       ;;
-       srlz.i
-       ;;
-       mov ar.lc=r9
-       mov r8=r0
-       ;;
-1:     cmp.eq p6,p7=PAL_PERF_MON_INFO,r28
-(p7)   br.cond.sptk.few 1f
-       mov r8=0                        /* status = 0 */
-       movl r9 =0x08122f04             /* generic=4 width=47 retired=8 cycles=18 */
-       mov r10=0                       /* reserved */
-       mov r11=0                       /* reserved */
-       mov r16=0xffff                  /* implemented PMC */
-       mov r17=0x3ffff                 /* implemented PMD */
-       add r18=8,r29                   /* second index */
-       ;;
-       st8 [r29]=r16,16                /* store implemented PMC */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-       st8 [r29]=r0,16                 /* clear remaining bits  */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-       st8 [r29]=r17,16                /* store implemented PMD */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       mov r16=0xf0                    /* cycles count capable PMC */
-       ;;
-       st8 [r29]=r0,16                 /* clear remaining bits  */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       mov r17=0xf0                    /* retired bundles capable PMC */
-       ;;
-       st8 [r29]=r16,16                /* store cycles capable */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-       st8 [r29]=r0,16                 /* clear remaining bits  */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-       st8 [r29]=r17,16                /* store retired bundle capable */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-       st8 [r29]=r0,16                 /* clear remaining bits  */
-       st8 [r18]=r0,16                 /* clear remaining bits  */
-       ;;
-1:     cmp.eq p6,p7=PAL_VM_SUMMARY,r28
-(p7)   br.cond.sptk.few 1f
-       mov     r8=0                    /* status = 0  */
-       movl    r9=0x2044040020F1865    /* num_tc_levels=2, num_unique_tcs=4 */
-                                       /* max_itr_entry=64, max_dtr_entry=64 */
-                                       /* hash_tag_id=2, max_pkr=15 */
-                                       /* key_size=24, phys_add_size=50, vw=1 */
-       movl    r10=0x183C              /* rid_size=24, impl_va_msb=60 */
-       ;;
-1:     cmp.eq p6,p7=PAL_MEM_ATTRIB,r28
-(p7)   br.cond.sptk.few 1f
-       mov     r8=0                    /* status = 0 */
-       mov     r9=0x80|0x01            /* NatPage|WB */
-       ;;
-1:     br.cond.sptk.few rp
-stacked:
-       br.ret.sptk.few rp
-END(pal_emulator_static)
diff --git a/arch/ia64/hp/sim/boot/bootloader.c b/arch/ia64/hp/sim/boot/bootloader.c
deleted file mode 100644 (file)
index 6d80460..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * arch/ia64/hp/sim/boot/bootloader.c
- *
- * Loads an ELF kernel.
- *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *     Stephane Eranian <eranian@hpl.hp.com>
- *
- * 01/07/99 S.Eranian modified to pass command line arguments to kernel
- */
-struct task_struct;    /* forward declaration for elf.h */
-
-#include <linux/elf.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/elf.h>
-#include <asm/intrinsics.h>
-#include <asm/pal.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
-
-#include "ssc.h"
-
-struct disk_req {
-       unsigned long addr;
-       unsigned len;
-};
-
-struct disk_stat {
-       int fd;
-       unsigned count;
-};
-
-extern void jmp_to_kernel (unsigned long bp, unsigned long e_entry);
-extern struct ia64_boot_param *sys_fw_init (const char *args, int arglen);
-extern void debug_break (void);
-
-static void
-cons_write (const char *buf)
-{
-       unsigned long ch;
-
-       while ((ch = *buf++) != '\0') {
-               ssc(ch, 0, 0, 0, SSC_PUTCHAR);
-               if (ch == '\n')
-                 ssc('\r', 0, 0, 0, SSC_PUTCHAR);
-       }
-}
-
-#define MAX_ARGS 32
-
-void
-start_bootloader (void)
-{
-       static char mem[4096];
-       static char buffer[1024];
-       unsigned long off;
-       int fd, i;
-       struct disk_req req;
-       struct disk_stat stat;
-       struct elfhdr *elf;
-       struct elf_phdr *elf_phdr;      /* program header */
-       unsigned long e_entry, e_phoff, e_phnum;
-       register struct ia64_boot_param *bp;
-       char *kpath, *args;
-       long arglen = 0;
-
-       ssc(0, 0, 0, 0, SSC_CONSOLE_INIT);
-
-       /*
-        * S.Eranian: extract the commandline argument from the simulator
-        *
-        * The expected format is as follows:
-         *
-        *      kernelname args...
-        *
-        * Both are optional but you can't have the second one without the first.
-        */
-       arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS);
-
-       kpath = "vmlinux";
-       args = buffer;
-       if (arglen > 0) {
-               kpath = buffer;
-               while (*args != ' ' && *args != '\0')
-                       ++args, --arglen;
-               if (*args == ' ')
-                       *args++ = '\0', --arglen;
-       }
-
-       if (arglen <= 0) {
-               args = "";
-               arglen = 1;
-       }
-
-       fd = ssc((long) kpath, 1, 0, 0, SSC_OPEN);
-
-       if (fd < 0) {
-               cons_write(kpath);
-               cons_write(": file not found, reboot now\n");
-               for(;;);
-       }
-       stat.fd = fd;
-       off = 0;
-
-       req.len = sizeof(mem);
-       req.addr = (long) mem;
-       ssc(fd, 1, (long) &req, off, SSC_READ);
-       ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
-
-       elf = (struct elfhdr *) mem;
-       if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) != 0) {
-               cons_write("not an ELF file\n");
-               return;
-       }
-       if (elf->e_type != ET_EXEC) {
-               cons_write("not an ELF executable\n");
-               return;
-       }
-       if (!elf_check_arch(elf)) {
-               cons_write("kernel not for this processor\n");
-               return;
-       }
-
-       e_entry = elf->e_entry;
-       e_phnum = elf->e_phnum;
-       e_phoff = elf->e_phoff;
-
-       cons_write("loading ");
-       cons_write(kpath);
-       cons_write("...\n");
-
-       for (i = 0; i < e_phnum; ++i) {
-               req.len = sizeof(*elf_phdr);
-               req.addr = (long) mem;
-               ssc(fd, 1, (long) &req, e_phoff, SSC_READ);
-               ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
-               if (stat.count != sizeof(*elf_phdr)) {
-                       cons_write("failed to read phdr\n");
-                       return;
-               }
-               e_phoff += sizeof(*elf_phdr);
-
-               elf_phdr = (struct elf_phdr *) mem;
-
-               if (elf_phdr->p_type != PT_LOAD)
-                       continue;
-
-               req.len = elf_phdr->p_filesz;
-               req.addr = __pa(elf_phdr->p_paddr);
-               ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ);
-               ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION);
-               memset((char *)__pa(elf_phdr->p_paddr) + elf_phdr->p_filesz, 0,
-                      elf_phdr->p_memsz - elf_phdr->p_filesz);
-       }
-       ssc(fd, 0, 0, 0, SSC_CLOSE);
-
-       cons_write("starting kernel...\n");
-
-       /* fake an I/O base address: */
-       ia64_setreg(_IA64_REG_AR_KR0, 0xffffc000000UL);
-
-       bp = sys_fw_init(args, arglen);
-
-       ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
-
-       debug_break();
-       jmp_to_kernel((unsigned long) bp, e_entry);
-
-       cons_write("kernel returned!\n");
-       ssc(-1, 0, 0, 0, SSC_EXIT);
-}
diff --git a/arch/ia64/hp/sim/boot/bootloader.lds b/arch/ia64/hp/sim/boot/bootloader.lds
deleted file mode 100644 (file)
index f3f284d..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-OUTPUT_FORMAT("elf64-ia64-little")
-OUTPUT_ARCH(ia64)
-ENTRY(_start)
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = 0x100000;
-
-  _text = .;
-  .text : { *(__ivt_section) *(.text) }
-  _etext = .;
-
-  /* Global data */
-  _data = .;
-  .rodata : { *(.rodata) *(.rodata.*) }
-  .data    : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS }
-  __gp = ALIGN (8) + 0x200000;
-  .got           : { *(.got.plt) *(.got) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-
-  __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       : { *(.bss) *(COMMON) }
-  . = ALIGN(64 / 8);
-  __bss_stop = .;
-  _end = . ;
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging sections are relative to the beginning
-     of the section so we begin them at 0.  */
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-  /* These must appear regardless of  .  */
-}
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
deleted file mode 100644 (file)
index 517fb28..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * PAL & SAL emulation.
- *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#ifdef CONFIG_PCI
-# include <linux/pci.h>
-#endif
-
-#include <linux/efi.h>
-#include <asm/io.h>
-#include <asm/pal.h>
-#include <asm/sal.h>
-#include <asm/setup.h>
-
-#include "ssc.h"
-
-#define MB     (1024*1024UL)
-
-#define SIMPLE_MEMMAP  1
-
-#if SIMPLE_MEMMAP
-# define NUM_MEM_DESCS 4
-#else
-# define NUM_MEM_DESCS 16
-#endif
-
-static char fw_mem[(  sizeof(struct ia64_boot_param)
-                   + sizeof(efi_system_table_t)
-                   + sizeof(efi_runtime_services_t)
-                   + 1*sizeof(efi_config_table_t)
-                   + sizeof(struct ia64_sal_systab)
-                   + sizeof(struct ia64_sal_desc_entry_point)
-                   + NUM_MEM_DESCS*(sizeof(efi_memory_desc_t))
-                   + 1024)] __attribute__ ((aligned (8)));
-
-#define SECS_PER_HOUR   (60 * 60)
-#define SECS_PER_DAY    (SECS_PER_HOUR * 24)
-
-/* Compute the `struct tm' representation of *T,
-   offset OFFSET seconds east of UTC,
-   and store year, yday, mon, mday, wday, hour, min, sec into *TP.
-   Return nonzero if successful.  */
-int
-offtime (unsigned long t, efi_time_t *tp)
-{
-       const unsigned short int __mon_yday[2][13] =
-       {
-               /* Normal years.  */
-               { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
-               /* Leap years.  */
-               { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
-       };
-       long int days, rem, y;
-       const unsigned short int *ip;
-
-       days = t / SECS_PER_DAY;
-       rem = t % SECS_PER_DAY;
-       while (rem < 0) {
-               rem += SECS_PER_DAY;
-               --days;
-       }
-       while (rem >= SECS_PER_DAY) {
-               rem -= SECS_PER_DAY;
-               ++days;
-       }
-       tp->hour = rem / SECS_PER_HOUR;
-       rem %= SECS_PER_HOUR;
-       tp->minute = rem / 60;
-       tp->second = rem % 60;
-       /* January 1, 1970 was a Thursday.  */
-       y = 1970;
-
-#      define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#      define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
-#      define __isleap(year) \
-         ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-
-       while (days < 0 || days >= (__isleap (y) ? 366 : 365)) {
-               /* Guess a corrected year, assuming 365 days per year.  */
-               long int yg = y + days / 365 - (days % 365 < 0);
-
-               /* Adjust DAYS and Y to match the guessed year.  */
-               days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1)
-                        - LEAPS_THRU_END_OF (y - 1));
-               y = yg;
-       }
-       tp->year = y;
-       ip = __mon_yday[__isleap(y)];
-       for (y = 11; days < (long int) ip[y]; --y)
-               continue;
-       days -= ip[y];
-       tp->month = y + 1;
-       tp->day = days + 1;
-       return 1;
-}
-
-extern void pal_emulator_static (void);
-
-/* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */
-
-#define BUILD_CMD(addr)                ((0x80000000 | (addr)) & ~3)
-
-#define REG_OFFSET(addr)       (0x00000000000000FF & (addr))
-#define DEVICE_FUNCTION(addr)  (0x000000000000FF00 & (addr))
-#define BUS_NUMBER(addr)       (0x0000000000FF0000 & (addr))
-
-static efi_status_t
-fw_efi_get_time (efi_time_t *tm, efi_time_cap_t *tc)
-{
-#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC)
-       struct {
-               int tv_sec;     /* must be 32bits to work */
-               int tv_usec;
-       } tv32bits;
-
-       ssc((unsigned long) &tv32bits, 0, 0, 0, SSC_GET_TOD);
-
-       memset(tm, 0, sizeof(*tm));
-       offtime(tv32bits.tv_sec, tm);
-
-       if (tc)
-               memset(tc, 0, sizeof(*tc));
-#else
-#      error Not implemented yet...
-#endif
-       return EFI_SUCCESS;
-}
-
-static void
-efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data)
-{
-#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC)
-       ssc(status, 0, 0, 0, SSC_EXIT);
-#else
-#      error Not implemented yet...
-#endif
-}
-
-static efi_status_t
-efi_unimplemented (void)
-{
-       return EFI_UNSUPPORTED;
-}
-
-static struct sal_ret_values
-sal_emulator (long index, unsigned long in1, unsigned long in2,
-             unsigned long in3, unsigned long in4, unsigned long in5,
-             unsigned long in6, unsigned long in7)
-{
-       long r9  = 0;
-       long r10 = 0;
-       long r11 = 0;
-       long status;
-
-       /*
-        * Don't do a "switch" here since that gives us code that
-        * isn't self-relocatable.
-        */
-       status = 0;
-       if (index == SAL_FREQ_BASE) {
-               if (in1 == SAL_FREQ_BASE_PLATFORM)
-                       r9 = 200000000;
-               else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) {
-                       /*
-                        * Is this supposed to be the cr.itc frequency
-                        * or something platform specific?  The SAL
-                        * doc ain't exactly clear on this...
-                        */
-                       r9 = 700000000;
-               } else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK)
-                       r9 = 1;
-               else
-                       status = -1;
-       } else if (index == SAL_SET_VECTORS) {
-               ;
-       } else if (index == SAL_GET_STATE_INFO) {
-               ;
-       } else if (index == SAL_GET_STATE_INFO_SIZE) {
-               ;
-       } else if (index == SAL_CLEAR_STATE_INFO) {
-               ;
-       } else if (index == SAL_MC_RENDEZ) {
-               ;
-       } else if (index == SAL_MC_SET_PARAMS) {
-               ;
-       } else if (index == SAL_CACHE_FLUSH) {
-               ;
-       } else if (index == SAL_CACHE_INIT) {
-               ;
-#ifdef CONFIG_PCI
-       } else if (index == SAL_PCI_CONFIG_READ) {
-               /*
-                * in1 contains the PCI configuration address and in2
-                * the size of the read.  The value that is read is
-                * returned via the general register r9.
-                */
-                outl(BUILD_CMD(in1), 0xCF8);
-                if (in2 == 1)                           /* Reading byte  */
-                        r9 = inb(0xCFC + ((REG_OFFSET(in1) & 3)));
-                else if (in2 == 2)                      /* Reading word  */
-                        r9 = inw(0xCFC + ((REG_OFFSET(in1) & 2)));
-                else                                    /* Reading dword */
-                        r9 = inl(0xCFC);
-                status = PCIBIOS_SUCCESSFUL;
-       } else if (index == SAL_PCI_CONFIG_WRITE) {
-               /*
-                * in1 contains the PCI configuration address, in2 the
-                * size of the write, and in3 the actual value to be
-                * written out.
-                */
-                outl(BUILD_CMD(in1), 0xCF8);
-                if (in2 == 1)                           /* Writing byte  */
-                        outb(in3, 0xCFC + ((REG_OFFSET(in1) & 3)));
-                else if (in2 == 2)                      /* Writing word  */
-                        outw(in3, 0xCFC + ((REG_OFFSET(in1) & 2)));
-                else                                    /* Writing dword */
-                        outl(in3, 0xCFC);
-                status = PCIBIOS_SUCCESSFUL;
-#endif /* CONFIG_PCI */
-       } else if (index == SAL_UPDATE_PAL) {
-               ;
-       } else {
-               status = -1;
-       }
-       return ((struct sal_ret_values) {status, r9, r10, r11});
-}
-
-struct ia64_boot_param *
-sys_fw_init (const char *args, int arglen)
-{
-       efi_system_table_t *efi_systab;
-       efi_runtime_services_t *efi_runtime;
-       efi_config_table_t *efi_tables;
-       struct ia64_sal_systab *sal_systab;
-       efi_memory_desc_t *efi_memmap, *md;
-       unsigned long *pal_desc, *sal_desc;
-       struct ia64_sal_desc_entry_point *sal_ed;
-       struct ia64_boot_param *bp;
-       unsigned char checksum = 0;
-       char *cp, *cmd_line;
-       int i = 0;
-#      define MAKE_MD(typ, attr, start, end)           \
-       do {                                            \
-               md = efi_memmap + i++;                  \
-               md->type = typ;                         \
-               md->pad = 0;                            \
-               md->phys_addr = start;                  \
-               md->virt_addr = 0;                      \
-               md->num_pages = (end - start) >> 12;    \
-               md->attribute = attr;                   \
-       } while (0)
-
-       memset(fw_mem, 0, sizeof(fw_mem));
-
-       pal_desc = (unsigned long *) &pal_emulator_static;
-       sal_desc = (unsigned long *) &sal_emulator;
-
-       cp = fw_mem;
-       efi_systab  = (void *) cp; cp += sizeof(*efi_systab);
-       efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
-       efi_tables  = (void *) cp; cp += sizeof(*efi_tables);
-       sal_systab  = (void *) cp; cp += sizeof(*sal_systab);
-       sal_ed      = (void *) cp; cp += sizeof(*sal_ed);
-       efi_memmap  = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
-       bp          = (void *) cp; cp += sizeof(*bp);
-       cmd_line    = (void *) cp;
-
-       if (args) {
-               if (arglen >= 1024)
-                       arglen = 1023;
-               memcpy(cmd_line, args, arglen);
-       } else {
-               arglen = 0;
-       }
-       cmd_line[arglen] = '\0';
-
-       memset(efi_systab, 0, sizeof(*efi_systab));
-       efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
-       efi_systab->hdr.revision  = ((1 << 16) | 00);
-       efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
-       efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0");
-       efi_systab->fw_revision = 1;
-       efi_systab->runtime = (void *) __pa(efi_runtime);
-       efi_systab->nr_tables = 1;
-       efi_systab->tables = __pa(efi_tables);
-
-       efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
-       efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
-       efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
-       efi_runtime->get_time = (void *)__pa(&fw_efi_get_time);
-       efi_runtime->set_time = (void *)__pa(&efi_unimplemented);
-       efi_runtime->get_wakeup_time = (void *)__pa(&efi_unimplemented);
-       efi_runtime->set_wakeup_time = (void *)__pa(&efi_unimplemented);
-       efi_runtime->set_virtual_address_map = (void *)__pa(&efi_unimplemented);
-       efi_runtime->get_variable = (void *)__pa(&efi_unimplemented);
-       efi_runtime->get_next_variable = (void *)__pa(&efi_unimplemented);
-       efi_runtime->set_variable = (void *)__pa(&efi_unimplemented);
-       efi_runtime->get_next_high_mono_count = (void *)__pa(&efi_unimplemented);
-       efi_runtime->reset_system = (void *)__pa(&efi_reset_system);
-
-       efi_tables->guid = SAL_SYSTEM_TABLE_GUID;
-       efi_tables->table = __pa(sal_systab);
-
-       /* fill in the SAL system table: */
-       memcpy(sal_systab->signature, "SST_", 4);
-       sal_systab->size = sizeof(*sal_systab);
-       sal_systab->sal_rev_minor = 1;
-       sal_systab->sal_rev_major = 0;
-       sal_systab->entry_count = 1;
-
-#ifdef CONFIG_IA64_GENERIC
-        strcpy(sal_systab->oem_id, "Generic");
-        strcpy(sal_systab->product_id, "IA-64 system");
-#endif
-
-#ifdef CONFIG_IA64_HP_SIM
-       strcpy(sal_systab->oem_id, "Hewlett-Packard");
-       strcpy(sal_systab->product_id, "HP-simulator");
-#endif
-
-       /* fill in an entry point: */
-       sal_ed->type = SAL_DESC_ENTRY_POINT;
-       sal_ed->pal_proc = __pa(pal_desc[0]);
-       sal_ed->sal_proc = __pa(sal_desc[0]);
-       sal_ed->gp = __pa(sal_desc[1]);
-
-       for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
-               checksum += *cp;
-
-       sal_systab->checksum = -checksum;
-
-#if SIMPLE_MEMMAP
-       /* simulate free memory at physical address zero */
-       MAKE_MD(EFI_BOOT_SERVICES_DATA,         EFI_MEMORY_WB,    0*MB,    1*MB);
-       MAKE_MD(EFI_PAL_CODE,                   EFI_MEMORY_WB,    1*MB,    2*MB);
-       MAKE_MD(EFI_CONVENTIONAL_MEMORY,        EFI_MEMORY_WB,    2*MB,  130*MB);
-       MAKE_MD(EFI_CONVENTIONAL_MEMORY,        EFI_MEMORY_WB, 4096*MB, 4128*MB);
-#else
-       MAKE_MD( 4,                0x9, 0x0000000000000000, 0x0000000000001000);
-       MAKE_MD( 7,                0x9, 0x0000000000001000, 0x000000000008a000);
-       MAKE_MD( 4,                0x9, 0x000000000008a000, 0x00000000000a0000);
-       MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000);
-       MAKE_MD( 7,                0x9, 0x0000000000100000, 0x0000000004400000);
-       MAKE_MD( 2,                0x9, 0x0000000004400000, 0x0000000004be5000);
-       MAKE_MD( 7,                0x9, 0x0000000004be5000, 0x000000007f77e000);
-       MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000);
-       MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000);
-       MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000);
-       MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000);
-       MAKE_MD( 7,                0x9, 0x000000007fc3a000, 0x000000007fea0000);
-       MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000);
-       MAKE_MD( 7,                0x9, 0x000000007fea8000, 0x000000007feab000);
-       MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000);
-       MAKE_MD( 7,                0x9, 0x00000000ff400000, 0x0000000104000000);
-#endif
-
-       bp->efi_systab = __pa(&fw_mem);
-       bp->efi_memmap = __pa(efi_memmap);
-       bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t);
-       bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
-       bp->efi_memdesc_version = 1;
-       bp->command_line = __pa(cmd_line);
-       bp->console_info.num_cols = 80;
-       bp->console_info.num_rows = 25;
-       bp->console_info.orig_x = 0;
-       bp->console_info.orig_y = 24;
-       bp->fpswa = 0;
-
-       return bp;
-}
diff --git a/arch/ia64/hp/sim/boot/ssc.h b/arch/ia64/hp/sim/boot/ssc.h
deleted file mode 100644 (file)
index 88752c7..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *     Stephane Eranian <eranian@hpl.hp.com>
- */
-#ifndef ssc_h
-#define ssc_h
-
-/* Simulator system calls: */
-
-#define SSC_CONSOLE_INIT               20
-#define SSC_GETCHAR                    21
-#define SSC_PUTCHAR                    31
-#define SSC_OPEN                       50
-#define SSC_CLOSE                      51
-#define SSC_READ                       52
-#define SSC_WRITE                      53
-#define SSC_GET_COMPLETION             54
-#define SSC_WAIT_COMPLETION            55
-#define SSC_CONNECT_INTERRUPT          58
-#define SSC_GENERATE_INTERRUPT         59
-#define SSC_SET_PERIODIC_INTERRUPT     60
-#define SSC_GET_RTC                    65
-#define SSC_EXIT                       66
-#define SSC_LOAD_SYMBOLS               69
-#define SSC_GET_TOD                    74
-
-#define SSC_GET_ARGS                   75
-
-/*
- * Simulator system call.
- */
-extern long ssc (long arg0, long arg1, long arg2, long arg3, int nr);
-
-#endif /* ssc_h */
diff --git a/arch/ia64/hp/sim/hpsim.S b/arch/ia64/hp/sim/hpsim.S
deleted file mode 100644 (file)
index 44b4d53..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <asm/asmmacro.h>
-
-/*
- * Simulator system call.
- */
-GLOBAL_ENTRY(ia64_ssc)
-       mov r15=r36
-       break 0x80001
-       br.ret.sptk.many rp
-END(ia64_ssc)
diff --git a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c
deleted file mode 100644 (file)
index bffd9f6..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/kdev_t.h>
-#include <linux/console.h>
-
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/pal.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
-#include <asm/hpsim.h>
-
-#include "hpsim_ssc.h"
-
-static int simcons_init (struct console *, char *);
-static void simcons_write (struct console *, const char *, unsigned);
-static struct tty_driver *simcons_console_device (struct console *, int *);
-
-static struct console hpsim_cons = {
-       .name =         "simcons",
-       .write =        simcons_write,
-       .device =       simcons_console_device,
-       .setup =        simcons_init,
-       .flags =        CON_PRINTBUFFER,
-       .index =        -1,
-};
-
-static int
-simcons_init (struct console *cons, char *options)
-{
-       return 0;
-}
-
-static void
-simcons_write (struct console *cons, const char *buf, unsigned count)
-{
-       unsigned long ch;
-
-       while (count-- > 0) {
-               ch = *buf++;
-               ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR);
-               if (ch == '\n')
-                 ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
-       }
-}
-
-static struct tty_driver *simcons_console_device (struct console *c, int *index)
-{
-       *index = c->index;
-       return hp_simserial_driver;
-}
-
-int simcons_register(void)
-{
-       if (!ia64_platform_is("hpsim"))
-               return 1;
-
-       if (hpsim_cons.flags & CON_ENABLED)
-               return 1;
-
-       register_console(&hpsim_cons);
-       return 0;
-}
diff --git a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c
deleted file mode 100644 (file)
index 2f1cc59..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/irq.h>
-
-#include "hpsim_ssc.h"
-
-static unsigned int
-hpsim_irq_startup(struct irq_data *data)
-{
-       return 0;
-}
-
-static void
-hpsim_irq_noop(struct irq_data *data)
-{
-}
-
-static int
-hpsim_set_affinity_noop(struct irq_data *d, const struct cpumask *b, bool f)
-{
-       return 0;
-}
-
-static struct irq_chip irq_type_hp_sim = {
-       .name =                 "hpsim",
-       .irq_startup =          hpsim_irq_startup,
-       .irq_shutdown =         hpsim_irq_noop,
-       .irq_enable =           hpsim_irq_noop,
-       .irq_disable =          hpsim_irq_noop,
-       .irq_ack =              hpsim_irq_noop,
-       .irq_set_affinity =     hpsim_set_affinity_noop,
-};
-
-static void hpsim_irq_set_chip(int irq)
-{
-       struct irq_chip *chip = irq_get_chip(irq);
-
-       if (chip == &no_irq_chip)
-               irq_set_chip(irq, &irq_type_hp_sim);
-}
-
-static void hpsim_connect_irq(int intr, int irq)
-{
-       ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
-}
-
-int hpsim_get_irq(int intr)
-{
-       int irq = assign_irq_vector(AUTO_ASSIGN);
-
-       if (irq >= 0) {
-               hpsim_irq_set_chip(irq);
-               irq_set_handler(irq, handle_simple_irq);
-               hpsim_connect_irq(intr, irq);
-       }
-
-       return irq;
-}
-
-void __init
-hpsim_irq_init (void)
-{
-       int i;
-
-       for_each_active_irq(i)
-               hpsim_irq_set_chip(i);
-}
diff --git a/arch/ia64/hp/sim/hpsim_machvec.c b/arch/ia64/hp/sim/hpsim_machvec.c
deleted file mode 100644 (file)
index c214193..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MACHVEC_PLATFORM_NAME          hpsim
-#define MACHVEC_PLATFORM_HEADER                <asm/machvec_hpsim.h>
-#include <asm/machvec_init.h>
diff --git a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c
deleted file mode 100644 (file)
index 41d21d5..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/param.h>
-#include <linux/root_dev.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/pal.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
-#include <asm/hpsim.h>
-
-#include "hpsim_ssc.h"
-
-void
-ia64_ctl_trace (long on)
-{
-       ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
-}
-
-void __init
-hpsim_setup (char **cmdline_p)
-{
-       ROOT_DEV = Root_SDA1;           /* default to first SCSI drive */
-
-       simcons_register();
-}
diff --git a/arch/ia64/hp/sim/hpsim_ssc.h b/arch/ia64/hp/sim/hpsim_ssc.h
deleted file mode 100644 (file)
index 6fd97a4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
- */
-#ifndef _IA64_PLATFORM_HPSIM_SSC_H
-#define _IA64_PLATFORM_HPSIM_SSC_H
-
-/* Simulator system calls: */
-
-#define SSC_CONSOLE_INIT               20
-#define SSC_GETCHAR                    21
-#define SSC_PUTCHAR                    31
-#define SSC_CONNECT_INTERRUPT          58
-#define SSC_GENERATE_INTERRUPT         59
-#define SSC_SET_PERIODIC_INTERRUPT     60
-#define SSC_GET_RTC                    65
-#define SSC_EXIT                       66
-#define SSC_LOAD_SYMBOLS               69
-#define SSC_GET_TOD                    74
-#define SSC_CTL_TRACE                  76
-
-#define SSC_NETDEV_PROBE               100
-#define SSC_NETDEV_SEND                        101
-#define SSC_NETDEV_RECV                        102
-#define SSC_NETDEV_ATTACH              103
-#define SSC_NETDEV_DETACH              104
-
-/*
- * Simulator system call.
- */
-extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
-
-#endif /* _IA64_PLATFORM_HPSIM_SSC_H */
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
deleted file mode 100644 (file)
index f39ef2b..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Simulated Ethernet Driver
- *
- * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
- *     Stephane Eranian <eranian@hpl.hp.com>
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/notifier.h>
-#include <linux/bitops.h>
-#include <asm/irq.h>
-#include <asm/hpsim.h>
-
-#include "hpsim_ssc.h"
-
-#define SIMETH_RECV_MAX        10
-
-/*
- * Maximum possible received frame for Ethernet.
- * We preallocate an sk_buff of that size to avoid costly
- * memcpy for temporary buffer into sk_buff. We do basically
- * what's done in other drivers, like eepro with a ring.
- * The difference is, of course, that we don't have real DMA !!!
- */
-#define SIMETH_FRAME_SIZE      ETH_FRAME_LEN
-
-
-#define NETWORK_INTR                   8
-
-struct simeth_local {
-       struct net_device_stats stats;
-       int                     simfd;   /* descriptor in the simulator */
-};
-
-static int simeth_probe1(void);
-static int simeth_open(struct net_device *dev);
-static int simeth_close(struct net_device *dev);
-static int simeth_tx(struct sk_buff *skb, struct net_device *dev);
-static int simeth_rx(struct net_device *dev);
-static struct net_device_stats *simeth_get_stats(struct net_device *dev);
-static irqreturn_t simeth_interrupt(int irq, void *dev_id);
-static void set_multicast_list(struct net_device *dev);
-static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr);
-
-static char *simeth_version="0.3";
-
-/*
- * This variable is used to establish a mapping between the Linux/ia64 kernel
- * and the host linux kernel.
- *
- * As of today, we support only one card, even though most of the code
- * is ready for many more. The mapping is then:
- *     linux/ia64 -> linux/x86
- *        eth0    -> eth1
- *
- * In the future, we some string operations, we could easily support up
- * to 10 cards (0-9).
- *
- * The default mapping can be changed on the kernel command line by
- * specifying simeth=ethX (or whatever string you want).
- */
-static char *simeth_device="eth0";      /* default host interface to use */
-
-
-
-static volatile unsigned int card_count; /* how many cards "found" so far */
-static int simeth_debug;               /* set to 1 to get debug information */
-
-/*
- * Used to catch IFF_UP & IFF_DOWN events
- */
-static struct notifier_block simeth_dev_notifier = {
-       simeth_device_event,
-       NULL
-};
-
-
-/*
- * Function used when using a kernel command line option.
- *
- * Format: simeth=interface_name (like eth0)
- */
-static int __init
-simeth_setup(char *str)
-{
-       simeth_device = str;
-       return 1;
-}
-
-__setup("simeth=", simeth_setup);
-
-/*
- * Function used to probe for simeth devices when not installed
- * as a loadable module
- */
-
-int __init
-simeth_probe (void)
-{
-       int r;
-
-       printk(KERN_INFO "simeth: v%s\n", simeth_version);
-
-       r = simeth_probe1();
-
-       if (r == 0) register_netdevice_notifier(&simeth_dev_notifier);
-
-       return r;
-}
-
-static inline int
-netdev_probe(char *name, unsigned char *ether)
-{
-       return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE);
-}
-
-
-static inline int
-netdev_attach(int fd, int irq, unsigned int ipaddr)
-{
-       /* this puts the host interface in the right mode (start interrupting) */
-       return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH);
-}
-
-
-static inline int
-netdev_detach(int fd)
-{
-       /*
-        * inactivate the host interface (don't interrupt anymore) */
-       return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH);
-}
-
-static inline int
-netdev_send(int fd, unsigned char *buf, unsigned int len)
-{
-       return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND);
-}
-
-static inline int
-netdev_read(int fd, unsigned char *buf, unsigned int len)
-{
-       return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV);
-}
-
-static const struct net_device_ops simeth_netdev_ops = {
-       .ndo_open               = simeth_open,
-       .ndo_stop               = simeth_close,
-       .ndo_start_xmit         = simeth_tx,
-       .ndo_get_stats          = simeth_get_stats,
-       .ndo_set_rx_mode        = set_multicast_list, /* not yet used */
-
-};
-
-/*
- * Function shared with module code, so cannot be in init section
- *
- * So far this function "detects" only one card (test_&_set) but could
- * be extended easily.
- *
- * Return:
- *     - -ENODEV is no device found
- *     - -ENOMEM is no more memory
- *     - 0 otherwise
- */
-static int
-simeth_probe1(void)
-{
-       unsigned char mac_addr[ETH_ALEN];
-       struct simeth_local *local;
-       struct net_device *dev;
-       int fd, err, rc;
-
-       /*
-        * XXX Fix me
-        * let's support just one card for now
-        */
-       if (test_and_set_bit(0, &card_count))
-               return -ENODEV;
-
-       /*
-        * check with the simulator for the device
-        */
-       fd = netdev_probe(simeth_device, mac_addr);
-       if (fd == -1)
-               return -ENODEV;
-
-       dev = alloc_etherdev(sizeof(struct simeth_local));
-       if (!dev)
-               return -ENOMEM;
-
-       memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr));
-
-       local = netdev_priv(dev);
-       local->simfd = fd; /* keep track of underlying file descriptor */
-
-       dev->netdev_ops = &simeth_netdev_ops;
-
-       err = register_netdev(dev);
-       if (err) {
-               free_netdev(dev);
-               return err;
-       }
-
-       /*
-        * attach the interrupt in the simulator, this does enable interrupts
-        * until a netdev_attach() is called
-        */
-       if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0)
-               panic("%s: out of interrupt vectors!\n", __func__);
-       dev->irq = rc;
-
-       printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr=%pm, IRQ %d\n",
-              dev->name, simeth_device, local->simfd, dev->dev_addr, dev->irq);
-
-       return 0;
-}
-
-/*
- * actually binds the device to an interrupt vector
- */
-static int
-simeth_open(struct net_device *dev)
-{
-       if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) {
-               printk(KERN_WARNING "simeth: unable to get IRQ %d.\n", dev->irq);
-               return -EAGAIN;
-       }
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-/* copied from lapbether.c */
-static __inline__ int dev_is_ethdev(struct net_device *dev)
-{
-       return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5));
-}
-
-
-/*
- * Handler for IFF_UP or IFF_DOWN
- *
- * The reason for that is that we don't want to be interrupted when the
- * interface is down. There is no way to unconnect in the simualtor. Instead
- * we use this function to shutdown packet processing in the frame filter
- * in the simulator. Thus no interrupts are generated
- *
- *
- * That's also the place where we pass the IP address of this device to the
- * simulator so that that we can start filtering packets for it
- *
- * There may be a better way of doing this, but I don't know which yet.
- */
-static int
-simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
-{
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct simeth_local *local;
-       struct in_device *in_dev;
-       struct in_ifaddr **ifap = NULL;
-       struct in_ifaddr *ifa = NULL;
-       int r;
-
-
-       if ( ! dev ) {
-               printk(KERN_WARNING "simeth_device_event dev=0\n");
-               return NOTIFY_DONE;
-       }
-
-       if (dev_net(dev) != &init_net)
-               return NOTIFY_DONE;
-
-       if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE;
-
-       /*
-        * Check whether or not it's for an ethernet device
-        *
-        * XXX Fixme: This works only as long as we support one
-        * type of ethernet device.
-        */
-       if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE;
-
-       if ((in_dev=dev->ip_ptr) != NULL) {
-               for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
-                       if (strcmp(dev->name, ifa->ifa_label) == 0) break;
-       }
-       if ( ifa == NULL ) {
-               printk(KERN_ERR "simeth_open: can't find device %s's ifa\n", dev->name);
-               return NOTIFY_DONE;
-       }
-
-       printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n",
-              dev->name, ntohl(ifa->ifa_local));
-
-       /*
-        * XXX Fix me
-        * if the device was up, and we're simply reconfiguring it, not sure
-        * we get DOWN then UP.
-        */
-
-       local = netdev_priv(dev);
-       /* now do it for real */
-       r = event == NETDEV_UP ?
-               netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)):
-               netdev_detach(local->simfd);
-
-       printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n",
-              event == NETDEV_UP ? "attach":"detach", r);
-
-       return NOTIFY_DONE;
-}
-
-static int
-simeth_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-
-       free_irq(dev->irq, dev);
-
-       return 0;
-}
-
-/*
- * Only used for debug
- */
-static void
-frame_print(unsigned char *from, unsigned char *frame, int len)
-{
-       int i;
-
-       printk("%s: (%d) %02x", from, len, frame[0] & 0xff);
-       for(i=1; i < 6; i++ ) {
-               printk(":%02x", frame[i] &0xff);
-       }
-       printk(" %2x", frame[6] &0xff);
-       for(i=7; i < 12; i++ ) {
-               printk(":%02x", frame[i] &0xff);
-       }
-       printk(" [%02x%02x]\n", frame[12], frame[13]);
-
-       for(i=14; i < len; i++ ) {
-               printk("%02x ", frame[i] &0xff);
-               if ( (i%10)==0) printk("\n");
-       }
-       printk("\n");
-}
-
-
-/*
- * Function used to transmit of frame, very last one on the path before
- * going to the simulator.
- */
-static int
-simeth_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       struct simeth_local *local = netdev_priv(dev);
-
-#if 0
-       /* ensure we have at least ETH_ZLEN bytes (min frame size) */
-       unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-       /* Where do the extra padding bytes comes from inthe skbuff ? */
-#else
-       /* the real driver in the host system is going to take care of that
-        * or maybe it's the NIC itself.
-        */
-       unsigned int length = skb->len;
-#endif
-
-       local->stats.tx_bytes += skb->len;
-       local->stats.tx_packets++;
-
-
-       if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length);
-
-       netdev_send(local->simfd, skb->data, length);
-
-       /*
-        * we are synchronous on write, so we don't simulate a
-        * trasnmit complete interrupt, thus we don't need to arm a tx
-        */
-
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-static inline struct sk_buff *
-make_new_skb(struct net_device *dev)
-{
-       struct sk_buff *nskb;
-
-       /*
-        * The +2 is used to make sure that the IP header is nicely
-        * aligned (on 4byte boundary I assume 14+2=16)
-        */
-       nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2);
-       if ( nskb == NULL ) {
-               printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name);
-               return NULL;
-       }
-
-       skb_reserve(nskb, 2);   /* Align IP on 16 byte boundaries */
-
-       skb_put(nskb,SIMETH_FRAME_SIZE);
-
-       return nskb;
-}
-
-/*
- * called from interrupt handler to process a received frame
- */
-static int
-simeth_rx(struct net_device *dev)
-{
-       struct simeth_local     *local;
-       struct sk_buff          *skb;
-       int                     len;
-       int                     rcv_count = SIMETH_RECV_MAX;
-
-       local = netdev_priv(dev);
-       /*
-        * the loop concept has been borrowed from other drivers
-        * looks to me like it's a throttling thing to avoid pushing to many
-        * packets at one time into the stack. Making sure we can process them
-        * upstream and make forward progress overall
-        */
-       do {
-               if ( (skb=make_new_skb(dev)) == NULL ) {
-                       printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name);
-                       local->stats.rx_dropped++;
-                       return 0;
-               }
-               /*
-                * Read only one frame at a time
-                */
-               len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE);
-               if ( len == 0 ) {
-                       if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n",
-                                                      dev->name, SIMETH_RECV_MAX-rcv_count);
-                       break;
-               }
-#if 0
-               /*
-                * XXX Fix me
-                * Should really do a csum+copy here
-                */
-               skb_copy_to_linear_data(skb, frame, len);
-#endif
-               skb->protocol = eth_type_trans(skb, dev);
-
-               if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len);
-
-               /*
-                * push the packet up & trigger software interrupt
-                */
-               netif_rx(skb);
-
-               local->stats.rx_packets++;
-               local->stats.rx_bytes += len;
-
-       } while ( --rcv_count );
-
-       return len; /* 0 = nothing left to read, otherwise, we can try again */
-}
-
-/*
- * Interrupt handler (Yes, we can do it too !!!)
- */
-static irqreturn_t
-simeth_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-
-       /*
-        * very simple loop because we get interrupts only when receiving
-        */
-       while (simeth_rx(dev));
-       return IRQ_HANDLED;
-}
-
-static struct net_device_stats *
-simeth_get_stats(struct net_device *dev)
-{
-       struct simeth_local *local = netdev_priv(dev);
-
-       return &local->stats;
-}
-
-/* fake multicast ability */
-static void
-set_multicast_list(struct net_device *dev)
-{
-       printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name);
-}
-
-__initcall(simeth_probe);
diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
deleted file mode 100644 (file)
index 0a8a742..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Simulated SCSI driver.
- *
- * Copyright (C) 1999, 2001-2003 Hewlett-Packard Co
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *     Stephane Eranian <eranian@hpl.hp.com>
- *
- * 02/01/15 David Mosberger    Updated for v2.5.1
- * 99/12/18 David Mosberger    Added support for READ10/WRITE10 needed by linux v2.3.33
- */
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <asm/irq.h>
-#include "hpsim_ssc.h"
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#define DEBUG_SIMSCSI  0
-
-#define SIMSCSI_REQ_QUEUE_LEN  64
-#define DEFAULT_SIMSCSI_ROOT   "/var/ski-disks/sd"
-
-/* Simulator system calls: */
-
-#define SSC_OPEN                       50
-#define SSC_CLOSE                      51
-#define SSC_READ                       52
-#define SSC_WRITE                      53
-#define SSC_GET_COMPLETION             54
-#define SSC_WAIT_COMPLETION            55
-
-#define SSC_WRITE_ACCESS               2
-#define SSC_READ_ACCESS                        1
-
-#if DEBUG_SIMSCSI
-  int simscsi_debug;
-# define DBG   simscsi_debug
-#else
-# define DBG   0
-#endif
-
-static struct Scsi_Host *host;
-
-static void simscsi_interrupt (unsigned long val);
-static DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0);
-
-struct disk_req {
-       unsigned long addr;
-       unsigned len;
-};
-
-struct disk_stat {
-       int fd;
-       unsigned count;
-};
-
-static int desc[16] = {
-       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
-};
-
-static struct queue_entry {
-       struct scsi_cmnd *sc;
-} queue[SIMSCSI_REQ_QUEUE_LEN];
-
-static int rd, wr;
-static atomic_t num_reqs = ATOMIC_INIT(0);
-
-/* base name for default disks */
-static char *simscsi_root = DEFAULT_SIMSCSI_ROOT;
-
-#define MAX_ROOT_LEN   128
-
-/*
- * used to setup a new base for disk images
- * to use /foo/bar/disk[a-z] as disk images
- * you have to specify simscsi=/foo/bar/disk on the command line
- */
-static int __init
-simscsi_setup (char *s)
-{
-       /* XXX Fix me we may need to strcpy() ? */
-       if (strlen(s) > MAX_ROOT_LEN) {
-               printk(KERN_ERR "simscsi_setup: prefix too long---using default %s\n",
-                      simscsi_root);
-       } else
-               simscsi_root = s;
-       return 1;
-}
-
-__setup("simscsi=", simscsi_setup);
-
-static void
-simscsi_interrupt (unsigned long val)
-{
-       struct scsi_cmnd *sc;
-
-       while ((sc = queue[rd].sc) != NULL) {
-               atomic_dec(&num_reqs);
-               queue[rd].sc = NULL;
-               if (DBG)
-                       printk("simscsi_interrupt: done with %u\n",
-                              sc->request->tag);
-               (*sc->scsi_done)(sc);
-               rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN;
-       }
-}
-
-static int
-simscsi_biosparam (struct scsi_device *sdev, struct block_device *n,
-               sector_t capacity, int ip[])
-{
-       ip[0] = 64;             /* heads */
-       ip[1] = 32;             /* sectors */
-       ip[2] = capacity >> 11; /* cylinders */
-       return 0;
-}
-
-static void
-simscsi_sg_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset)
-{
-       int i;
-       struct scatterlist *sl;
-       struct disk_stat stat;
-       struct disk_req req;
-
-       stat.fd = desc[sc->device->id];
-
-       scsi_for_each_sg(sc, sl, scsi_sg_count(sc), i) {
-               req.addr = __pa(sg_virt(sl));
-               req.len  = sl->length;
-               if (DBG)
-                       printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n",
-                              mode == SSC_READ ? "read":"write", req.addr, offset,
-                              scsi_sg_count(sc) - i, sl->length);
-               ia64_ssc(stat.fd, 1, __pa(&req), offset, mode);
-               ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION);
-
-               /* should not happen in our case */
-               if (stat.count != req.len) {
-                       sc->result = DID_ERROR << 16;
-                       return;
-               }
-               offset +=  sl->length;
-       }
-       sc->result = GOOD;
-}
-
-/*
- * function handling both READ_6/WRITE_6 (non-scatter/gather mode)
- * commands.
- * Added 02/26/99 S.Eranian
- */
-static void
-simscsi_readwrite6 (struct scsi_cmnd *sc, int mode)
-{
-       unsigned long offset;
-
-       offset = (((sc->cmnd[1] & 0x1f) << 16) | (sc->cmnd[2] << 8) | sc->cmnd[3])*512;
-       simscsi_sg_readwrite(sc, mode, offset);
-}
-
-static size_t
-simscsi_get_disk_size (int fd)
-{
-       struct disk_stat stat;
-       size_t bit, sectors = 0;
-       struct disk_req req;
-       char buf[512];
-
-       /*
-        * This is a bit kludgey: the simulator doesn't provide a
-        * direct way of determining the disk size, so we do a binary
-        * search, assuming a maximum disk size of 128GB.
-        */
-       for (bit = (128UL << 30)/512; bit != 0; bit >>= 1) {
-               req.addr = __pa(&buf);
-               req.len = sizeof(buf);
-               ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ);
-               stat.fd = fd;
-               ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION);
-               if (stat.count == sizeof(buf))
-                       sectors |= bit;
-       }
-       return sectors - 1;     /* return last valid sector number */
-}
-
-static void
-simscsi_readwrite10 (struct scsi_cmnd *sc, int mode)
-{
-       unsigned long offset;
-
-       offset = (((unsigned long)sc->cmnd[2] << 24) 
-               | ((unsigned long)sc->cmnd[3] << 16)
-               | ((unsigned long)sc->cmnd[4] <<  8) 
-               | ((unsigned long)sc->cmnd[5] <<  0))*512UL;
-       simscsi_sg_readwrite(sc, mode, offset);
-}
-
-static int
-simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
-{
-       unsigned int target_id = sc->device->id;
-       char fname[MAX_ROOT_LEN+16];
-       size_t disk_size;
-       char *buf;
-       char localbuf[36];
-#if DEBUG_SIMSCSI
-       register long sp asm ("sp");
-
-       if (DBG)
-               printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%u,sp=%lx,done=%p\n",
-                      target_id, sc->cmnd[0], sc->request->tag, sp, done);
-#endif
-
-       sc->result = DID_BAD_TARGET << 16;
-       sc->scsi_done = done;
-       if (target_id <= 15 && sc->device->lun == 0) {
-               switch (sc->cmnd[0]) {
-                     case INQUIRY:
-                       if (scsi_bufflen(sc) < 35) {
-                               break;
-                       }
-                       sprintf (fname, "%s%c", simscsi_root, 'a' + target_id);
-                       desc[target_id] = ia64_ssc(__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
-                                                  0, 0, SSC_OPEN);
-                       if (desc[target_id] < 0) {
-                               /* disk doesn't exist... */
-                               break;
-                       }
-                       buf = localbuf;
-                       buf[0] = 0;     /* magnetic disk */
-                       buf[1] = 0;     /* not a removable medium */
-                       buf[2] = 2;     /* SCSI-2 compliant device */
-                       buf[3] = 2;     /* SCSI-2 response data format */
-                       buf[4] = 31;    /* additional length (bytes) */
-                       buf[5] = 0;     /* reserved */
-                       buf[6] = 0;     /* reserved */
-                       buf[7] = 0;     /* various flags */
-                       memcpy(buf + 8, "HP      SIMULATED DISK  0.00",  28);
-                       scsi_sg_copy_from_buffer(sc, buf, 36);
-                       sc->result = GOOD;
-                       break;
-
-                     case TEST_UNIT_READY:
-                       sc->result = GOOD;
-                       break;
-
-                     case READ_6:
-                       if (desc[target_id] < 0 )
-                               break;
-                       simscsi_readwrite6(sc, SSC_READ);
-                       break;
-
-                     case READ_10:
-                       if (desc[target_id] < 0 )
-                               break;
-                       simscsi_readwrite10(sc, SSC_READ);
-                       break;
-
-                     case WRITE_6:
-                       if (desc[target_id] < 0)
-                               break;
-                       simscsi_readwrite6(sc, SSC_WRITE);
-                       break;
-
-                     case WRITE_10:
-                       if (desc[target_id] < 0)
-                               break;
-                       simscsi_readwrite10(sc, SSC_WRITE);
-                       break;
-
-                     case READ_CAPACITY:
-                       if (desc[target_id] < 0 || scsi_bufflen(sc) < 8) {
-                               break;
-                       }
-                       buf = localbuf;
-                       disk_size = simscsi_get_disk_size(desc[target_id]);
-
-                       buf[0] = (disk_size >> 24) & 0xff;
-                       buf[1] = (disk_size >> 16) & 0xff;
-                       buf[2] = (disk_size >>  8) & 0xff;
-                       buf[3] = (disk_size >>  0) & 0xff;
-                       /* set block size of 512 bytes: */
-                       buf[4] = 0;
-                       buf[5] = 0;
-                       buf[6] = 2;
-                       buf[7] = 0;
-                       scsi_sg_copy_from_buffer(sc, buf, 8);
-                       sc->result = GOOD;
-                       break;
-
-                     case MODE_SENSE:
-                     case MODE_SENSE_10:
-                       /* sd.c uses this to determine whether disk does write-caching. */
-                       scsi_sg_copy_from_buffer(sc, (char *)empty_zero_page,
-                                                PAGE_SIZE);
-                       sc->result = GOOD;
-                       break;
-
-                     case START_STOP:
-                       printk(KERN_ERR "START_STOP\n");
-                       break;
-
-                     default:
-                       panic("simscsi: unknown SCSI command %u\n", sc->cmnd[0]);
-               }
-       }
-       if (sc->result == DID_BAD_TARGET) {
-               sc->result |= DRIVER_SENSE << 24;
-               sc->sense_buffer[0] = 0x70;
-               sc->sense_buffer[2] = 0x00;
-       }
-       if (atomic_read(&num_reqs) >= SIMSCSI_REQ_QUEUE_LEN) {
-               panic("Attempt to queue command while command is pending!!");
-       }
-       atomic_inc(&num_reqs);
-       queue[wr].sc = sc;
-       wr = (wr + 1) % SIMSCSI_REQ_QUEUE_LEN;
-
-       tasklet_schedule(&simscsi_tasklet);
-       return 0;
-}
-
-static DEF_SCSI_QCMD(simscsi_queuecommand)
-
-static int
-simscsi_host_reset (struct scsi_cmnd *sc)
-{
-       printk(KERN_ERR "simscsi_host_reset: not implemented\n");
-       return 0;
-}
-
-static struct scsi_host_template driver_template = {
-       .name                   = "simulated SCSI host adapter",
-       .proc_name              = "simscsi",
-       .queuecommand           = simscsi_queuecommand,
-       .eh_host_reset_handler  = simscsi_host_reset,
-       .bios_param             = simscsi_biosparam,
-       .can_queue              = SIMSCSI_REQ_QUEUE_LEN,
-       .this_id                = -1,
-       .sg_tablesize           = SG_ALL,
-       .max_sectors            = 1024,
-       .cmd_per_lun            = SIMSCSI_REQ_QUEUE_LEN,
-       .dma_boundary           = PAGE_SIZE - 1,
-};
-
-static int __init
-simscsi_init(void)
-{
-       int error;
-
-       host = scsi_host_alloc(&driver_template, 0);
-       if (!host)
-               return -ENOMEM;
-
-       error = scsi_add_host(host, NULL);
-       if (error)
-               goto free_host;
-       scsi_scan_host(host);
-       return 0;
-
- free_host:
-       scsi_host_put(host);
-       return error;
-}
-device_initcall(simscsi_init);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
deleted file mode 100644 (file)
index 1a338e5..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Simulated Serial Driver (fake serial)
- *
- * This driver is mostly used for bringup purposes and will go away.
- * It has a strong dependency on the system console. All outputs
- * are rerouted to the same facility as the one used by printk which, in our
- * case means sys_sim.c console (goes via the simulator).
- *
- * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co
- *     Stephane Eranian <eranian@hpl.hp.com>
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/sched/debug.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/capability.h>
-#include <linux/circ_buf.h>
-#include <linux/console.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/uaccess.h>
-
-#include <asm/hpsim.h>
-
-#include "hpsim_ssc.h"
-
-#undef SIMSERIAL_DEBUG /* define this to get some debug information */
-
-#define KEYBOARD_INTR  3       /* must match with simulator! */
-
-#define NR_PORTS       1       /* only one port for now */
-
-struct serial_state {
-       struct tty_port port;
-       struct circ_buf xmit;
-       int irq;
-       int x_char;
-};
-
-static struct serial_state rs_table[NR_PORTS];
-
-struct tty_driver *hp_simserial_driver;
-
-static struct console *console;
-
-static void receive_chars(struct tty_port *port)
-{
-       unsigned char ch;
-       static unsigned char seen_esc = 0;
-
-       while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
-               if (ch == 27 && seen_esc == 0) {
-                       seen_esc = 1;
-                       continue;
-               } else if (seen_esc == 1 && ch == 'O') {
-                       seen_esc = 2;
-                       continue;
-               } else if (seen_esc == 2) {
-                       if (ch == 'P') /* F1 */
-                               show_state();
-#ifdef CONFIG_MAGIC_SYSRQ
-                       if (ch == 'S') { /* F4 */
-                               do {
-                                       ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
-                               } while (!ch);
-                               handle_sysrq(ch);
-                       }
-#endif
-                       seen_esc = 0;
-                       continue;
-               }
-               seen_esc = 0;
-
-               if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0)
-                       break;
-       }
-       tty_flip_buffer_push(port);
-}
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
-{
-       struct serial_state *info = dev_id;
-
-       receive_chars(&info->port);
-
-       return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static int rs_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       struct serial_state *info = tty->driver_data;
-       unsigned long flags;
-
-       if (!info->xmit.buf)
-               return 0;
-
-       local_irq_save(flags);
-       if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
-               local_irq_restore(flags);
-               return 0;
-       }
-       info->xmit.buf[info->xmit.head] = ch;
-       info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
-       local_irq_restore(flags);
-       return 1;
-}
-
-static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
-               int *intr_done)
-{
-       int count;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       if (info->x_char) {
-               char c = info->x_char;
-
-               console->write(console, &c, 1);
-
-               info->x_char = 0;
-
-               goto out;
-       }
-
-       if (info->xmit.head == info->xmit.tail || tty->stopped) {
-#ifdef SIMSERIAL_DEBUG
-               printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
-                      info->xmit.head, info->xmit.tail, tty->stopped);
-#endif
-               goto out;
-       }
-       /*
-        * We removed the loop and try to do it in to chunks. We need
-        * 2 operations maximum because it's a ring buffer.
-        *
-        * First from current to tail if possible.
-        * Then from the beginning of the buffer until necessary
-        */
-
-       count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
-                   SERIAL_XMIT_SIZE - info->xmit.tail);
-       console->write(console, info->xmit.buf+info->xmit.tail, count);
-
-       info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1);
-
-       /*
-        * We have more at the beginning of the buffer
-        */
-       count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-       if (count) {
-               console->write(console, info->xmit.buf, count);
-               info->xmit.tail += count;
-       }
-out:
-       local_irq_restore(flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-       struct serial_state *info = tty->driver_data;
-
-       if (info->xmit.head == info->xmit.tail || tty->stopped ||
-                       !info->xmit.buf)
-               return;
-
-       transmit_chars(tty, info, NULL);
-}
-
-static int rs_write(struct tty_struct * tty,
-                   const unsigned char *buf, int count)
-{
-       struct serial_state *info = tty->driver_data;
-       int     c, ret = 0;
-       unsigned long flags;
-
-       if (!info->xmit.buf)
-               return 0;
-
-       local_irq_save(flags);
-       while (1) {
-               c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-               if (count < c)
-                       c = count;
-               if (c <= 0) {
-                       break;
-               }
-               memcpy(info->xmit.buf + info->xmit.head, buf, c);
-               info->xmit.head = ((info->xmit.head + c) &
-                                  (SERIAL_XMIT_SIZE-1));
-               buf += c;
-               count -= c;
-               ret += c;
-       }
-       local_irq_restore(flags);
-       /*
-        * Hey, we transmit directly from here in our case
-        */
-       if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
-                       !tty->stopped)
-               transmit_chars(tty, info, NULL);
-
-       return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-       struct serial_state *info = tty->driver_data;
-
-       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
-       struct serial_state *info = tty->driver_data;
-
-       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
-       struct serial_state *info = tty->driver_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       info->xmit.head = info->xmit.tail = 0;
-       local_irq_restore(flags);
-
-       tty_wakeup(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_send_xchar(struct tty_struct *tty, char ch)
-{
-       struct serial_state *info = tty->driver_data;
-
-       info->x_char = ch;
-       if (ch) {
-               /*
-                * I guess we could call console->write() directly but
-                * let's do that for now.
-                */
-               transmit_chars(tty, info, NULL);
-       }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
-       if (I_IXOFF(tty))
-               rs_send_xchar(tty, STOP_CHAR(tty));
-
-       printk(KERN_INFO "simrs_throttle called\n");
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-       struct serial_state *info = tty->driver_data;
-
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       rs_send_xchar(tty, START_CHAR(tty));
-       }
-       printk(KERN_INFO "simrs_unthrottle called\n");
-}
-
-static int rs_setserial(struct tty_struct *tty, struct serial_struct *ss)
-{
-       return 0;
-}
-
-static int rs_getserial(struct tty_struct *tty, struct serial_struct *ss)
-{
-       return 0;
-}
-
-static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
-{
-       if ((cmd != TIOCSERCONFIG) && (cmd != TIOCMIWAIT)) {
-               if (tty_io_error(tty))
-                   return -EIO;
-       }
-
-       switch (cmd) {
-       case TIOCMIWAIT:
-               return 0;
-       case TIOCSERCONFIG:
-       case TIOCSERGETLSR: /* Get line status register */
-               return -EINVAL;
-       }
-       return -ENOIOCTLCMD;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct tty_port *port)
-{
-       struct serial_state *info = container_of(port, struct serial_state,
-                       port);
-       unsigned long flags;
-
-       local_irq_save(flags);
-       if (info->irq)
-               free_irq(info->irq, info);
-
-       if (info->xmit.buf) {
-               free_page((unsigned long) info->xmit.buf);
-               info->xmit.buf = NULL;
-       }
-       local_irq_restore(flags);
-}
-
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
-       struct serial_state *info = tty->driver_data;
-
-       tty_port_close(&info->port, tty, filp);
-}
-
-static void rs_hangup(struct tty_struct *tty)
-{
-       struct serial_state *info = tty->driver_data;
-
-       rs_flush_buffer(tty);
-       tty_port_hangup(&info->port);
-}
-
-static int activate(struct tty_port *port, struct tty_struct *tty)
-{
-       struct serial_state *state = container_of(port, struct serial_state,
-                       port);
-       unsigned long flags, page;
-       int retval = 0;
-
-       page = get_zeroed_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-
-       local_irq_save(flags);
-
-       if (state->xmit.buf)
-               free_page(page);
-       else
-               state->xmit.buf = (unsigned char *) page;
-
-       if (state->irq) {
-               retval = request_irq(state->irq, rs_interrupt_single, 0,
-                               "simserial", state);
-               if (retval)
-                       goto errout;
-       }
-
-       state->xmit.head = state->xmit.tail = 0;
-errout:
-       local_irq_restore(flags);
-       return retval;
-}
-
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
-       struct serial_state *info = rs_table + tty->index;
-       struct tty_port *port = &info->port;
-
-       tty->driver_data = info;
-       port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-       /*
-        * figure out which console to use (should be one already)
-        */
-       console = console_drivers;
-       while (console) {
-               if ((console->flags & CON_ENABLED) && console->write) break;
-               console = console->next;
-       }
-
-       return tty_port_open(port, tty, filp);
-}
-
-/*
- * /proc fs routines....
- */
-
-static int rs_proc_show(struct seq_file *m, void *v)
-{
-       int i;
-
-       seq_printf(m, "simserinfo:1.0\n");
-       for (i = 0; i < NR_PORTS; i++)
-               seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n",
-                      i, rs_table[i].irq);
-       return 0;
-}
-
-static const struct tty_operations hp_ops = {
-       .open = rs_open,
-       .close = rs_close,
-       .write = rs_write,
-       .put_char = rs_put_char,
-       .flush_chars = rs_flush_chars,
-       .write_room = rs_write_room,
-       .chars_in_buffer = rs_chars_in_buffer,
-       .flush_buffer = rs_flush_buffer,
-       .ioctl = rs_ioctl,
-       .throttle = rs_throttle,
-       .unthrottle = rs_unthrottle,
-       .send_xchar = rs_send_xchar,
-       .set_serial = rs_setserial,
-       .get_serial = rs_getserial,
-       .hangup = rs_hangup,
-       .proc_show = rs_proc_show,
-};
-
-static const struct tty_port_operations hp_port_ops = {
-       .activate = activate,
-       .shutdown = shutdown,
-};
-
-static int __init simrs_init(void)
-{
-       struct serial_state *state;
-       int retval;
-
-       if (!ia64_platform_is("hpsim"))
-               return -ENODEV;
-
-       hp_simserial_driver = alloc_tty_driver(NR_PORTS);
-       if (!hp_simserial_driver)
-               return -ENOMEM;
-
-       printk(KERN_INFO "SimSerial driver with no serial options enabled\n");
-
-       /* Initialize the tty_driver structure */
-
-       hp_simserial_driver->driver_name = "simserial";
-       hp_simserial_driver->name = "ttyS";
-       hp_simserial_driver->major = TTY_MAJOR;
-       hp_simserial_driver->minor_start = 64;
-       hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL;
-       hp_simserial_driver->init_termios = tty_std_termios;
-       hp_simserial_driver->init_termios.c_cflag =
-               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(hp_simserial_driver, &hp_ops);
-
-       state = rs_table;
-       tty_port_init(&state->port);
-       state->port.ops = &hp_port_ops;
-       state->port.close_delay = 0; /* XXX really 0? */
-
-       retval = hpsim_get_irq(KEYBOARD_INTR);
-       if (retval < 0) {
-               printk(KERN_ERR "%s: out of interrupt vectors!\n",
-                               __func__);
-               goto err_free_tty;
-       }
-
-       state->irq = retval;
-
-       /* the port is imaginary */
-       printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
-
-       tty_port_link_device(&state->port, hp_simserial_driver, 0);
-       retval = tty_register_driver(hp_simserial_driver);
-       if (retval) {
-               printk(KERN_ERR "Couldn't register simserial driver\n");
-               goto err_free_tty;
-       }
-
-       return 0;
-err_free_tty:
-       put_tty_driver(hp_simserial_driver);
-       tty_port_destroy(&state->port);
-       return retval;
-}
-
-#ifndef MODULE
-__initcall(simrs_init);
-#endif
diff --git a/arch/ia64/hp/zx1/Makefile b/arch/ia64/hp/zx1/Makefile
deleted file mode 100644 (file)
index 46b37d8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# ia64/hp/zx1/Makefile
-#
-# Copyright (C) 2002 Hewlett Packard
-# Copyright (C) Alex Williamson (alex_williamson@hp.com)
-#
-
-obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o hpzx1_swiotlb_machvec.o
diff --git a/arch/ia64/hp/zx1/hpzx1_machvec.c b/arch/ia64/hp/zx1/hpzx1_machvec.c
deleted file mode 100644 (file)
index 32518b0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MACHVEC_PLATFORM_NAME          hpzx1
-#define MACHVEC_PLATFORM_HEADER                <asm/machvec_hpzx1.h>
-#include <asm/machvec_init.h>
diff --git a/arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c b/arch/ia64/hp/zx1/hpzx1_swiotlb_machvec.c
deleted file mode 100644 (file)
index 4392a96..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#define MACHVEC_PLATFORM_NAME          hpzx1_swiotlb
-#define MACHVEC_PLATFORM_HEADER                <asm/machvec_hpzx1_swiotlb.h>
-#include <asm/machvec_init.h>
index 0ea5690..f886d4d 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/numa.h>
 #include <asm/numa.h>
 
-#ifdef CONFIG_ACPI
+
 extern int acpi_lapic;
 #define acpi_disabled 0        /* ACPI always enabled on IA64 */
 #define acpi_noirq 0   /* ACPI always enabled on IA64 */
@@ -28,34 +28,10 @@ static inline bool acpi_has_cpu_in_madt(void)
 {
        return !!acpi_lapic;
 }
-#endif
+
 #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
 static inline void disable_acpi(void) { }
 
-#ifdef CONFIG_IA64_GENERIC
-const char *acpi_get_sysname (void);
-#else
-static inline const char *acpi_get_sysname (void)
-{
-# if defined (CONFIG_IA64_HP_SIM)
-       return "hpsim";
-# elif defined (CONFIG_IA64_HP_ZX1)
-       return "hpzx1";
-# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
-       return "hpzx1_swiotlb";
-# elif defined (CONFIG_IA64_SGI_SN2)
-       return "sn2";
-# elif defined (CONFIG_IA64_SGI_UV)
-       return "uv";
-# elif defined (CONFIG_IA64_DIG)
-       return "dig";
-# elif defined(CONFIG_IA64_DIG_VTD)
-       return "dig_vtd";
-# else
-#      error Unknown platform.  Fix acpi.c.
-# endif
-}
-#endif
 int acpi_request_vector (u32 int_type);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
index f7ec71e..a5d9d78 100644 (file)
@@ -6,17 +6,11 @@
  * Copyright (C) 2003-2004 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
-#include <asm/machvec.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-debug.h>
-
 extern const struct dma_map_ops *dma_ops;
-extern struct ia64_machine_vector ia64_mv;
-extern void set_iommu_machvec(void);
 
 static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
 {
-       return platform_dma_get_ops(NULL);
+       return dma_ops;
 }
 
 #endif /* _ASM_IA64_DMA_MAPPING_H */
index 23604d6..59625e9 100644 (file)
 
 extern unsigned long MAX_DMA_ADDRESS;
 
-#ifdef CONFIG_PCI
-  extern int isa_dma_bridge_buggy;
-#else
-# define isa_dma_bridge_buggy  (0)
-#endif
+extern int isa_dma_bridge_buggy;
 
 #define free_dma(x)
 
diff --git a/arch/ia64/include/asm/hpsim.h b/arch/ia64/include/asm/hpsim.h
deleted file mode 100644 (file)
index 00fbd5c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASMIA64_HPSIM_H
-#define _ASMIA64_HPSIM_H
-
-#ifndef CONFIG_HP_SIMSERIAL_CONSOLE
-static inline int simcons_register(void) { return 1; }
-#else
-int simcons_register(void);
-#endif
-
-struct tty_driver;
-extern struct tty_driver *hp_simserial_driver;
-
-extern int hpsim_get_irq(int intr);
-void ia64_ctl_trace(long on);
-
-#endif
index 5dd3c64..e6385c7 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/types.h>
 #include <linux/profile.h>
 
-#include <asm/machvec.h>
 #include <asm/ptrace.h>
 #include <asm/smp.h>
 
@@ -56,7 +55,7 @@ typedef u8 ia64_vector;
 extern int ia64_first_device_vector;
 extern int ia64_last_device_vector;
 
-#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_DIG))
+#ifdef CONFIG_SMP
 /* Reserve the lower priority vector than device vectors for "move IRQ" IPI */
 #define IA64_IRQ_MOVE_VECTOR           0x30    /* "move IRQ" IPI */
 #define IA64_DEF_FIRST_DEVICE_VECTOR   0x31
@@ -127,7 +126,7 @@ extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
 extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action);
 extern void destroy_and_reserve_irq (unsigned int irq);
 
-#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+#ifdef CONFIG_SMP
 extern int irq_prepare_move(int irq, int cpu);
 extern void irq_complete_move(unsigned int irq);
 #else
@@ -137,25 +136,9 @@ static inline void irq_complete_move(unsigned int irq) {}
 
 static inline void ia64_native_resend_irq(unsigned int vector)
 {
-       platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
 }
 
-/*
- * Default implementations for the irq-descriptor API:
- */
-#ifndef CONFIG_IA64_GENERIC
-static inline ia64_vector __ia64_irq_to_vector(int irq)
-{
-       return irq_cfg[irq].vector;
-}
-
-static inline unsigned int
-__ia64_local_vector_to_irq (ia64_vector vec)
-{
-       return __this_cpu_read(vector_irq[vec]);
-}
-#endif
-
 /*
  * Next follows the irq descriptor interface.  On IA-64, each CPU supports 256 interrupt
  * vectors.  On smaller systems, there is a one-to-one correspondence between interrupt
@@ -170,7 +153,7 @@ __ia64_local_vector_to_irq (ia64_vector vec)
 static inline ia64_vector
 irq_to_vector (int irq)
 {
-       return platform_irq_to_vector(irq);
+       return irq_cfg[irq].vector;
 }
 
 /*
@@ -181,7 +164,7 @@ irq_to_vector (int irq)
 static inline unsigned int
 local_vector_to_irq (ia64_vector vec)
 {
-       return platform_local_vector_to_irq(vec);
+       return __this_cpu_read(vector_irq[vec]);
 }
 
 #endif /* _ASM_IA64_HW_IRQ_H */
index a511d62..54e70c2 100644 (file)
@@ -71,7 +71,6 @@ extern unsigned int num_io_spaces;
 #define HAVE_ARCH_PIO_SIZE
 
 #include <asm/intrinsics.h>
-#include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm-generic/iomap.h>
 
@@ -129,25 +128,6 @@ __ia64_mk_io_addr (unsigned long port)
        return (void *) (space->mmio_base | offset);
 }
 
-#define __ia64_inb     ___ia64_inb
-#define __ia64_inw     ___ia64_inw
-#define __ia64_inl     ___ia64_inl
-#define __ia64_outb    ___ia64_outb
-#define __ia64_outw    ___ia64_outw
-#define __ia64_outl    ___ia64_outl
-#define __ia64_readb   ___ia64_readb
-#define __ia64_readw   ___ia64_readw
-#define __ia64_readl   ___ia64_readl
-#define __ia64_readq   ___ia64_readq
-#define __ia64_readb_relaxed   ___ia64_readb
-#define __ia64_readw_relaxed   ___ia64_readw
-#define __ia64_readl_relaxed   ___ia64_readl
-#define __ia64_readq_relaxed   ___ia64_readq
-#define __ia64_writeb  ___ia64_writeb
-#define __ia64_writew  ___ia64_writew
-#define __ia64_writel  ___ia64_writel
-#define __ia64_writeq  ___ia64_writeq
-
 /*
  * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure
  * that the access has completed before executing other I/O accesses.  Since we're doing
@@ -156,8 +136,8 @@ __ia64_mk_io_addr (unsigned long port)
  * during optimization, which is why we use "volatile" pointers.
  */
 
-static inline unsigned int
-___ia64_inb (unsigned long port)
+#define inb inb
+static inline unsigned int inb(unsigned long port)
 {
        volatile unsigned char *addr = __ia64_mk_io_addr(port);
        unsigned char ret;
@@ -167,8 +147,8 @@ ___ia64_inb (unsigned long port)
        return ret;
 }
 
-static inline unsigned int
-___ia64_inw (unsigned long port)
+#define inw inw
+static inline unsigned int inw(unsigned long port)
 {
        volatile unsigned short *addr = __ia64_mk_io_addr(port);
        unsigned short ret;
@@ -178,8 +158,8 @@ ___ia64_inw (unsigned long port)
        return ret;
 }
 
-static inline unsigned int
-___ia64_inl (unsigned long port)
+#define inl inl
+static inline unsigned int inl(unsigned long port)
 {
        volatile unsigned int *addr = __ia64_mk_io_addr(port);
        unsigned int ret;
@@ -189,8 +169,8 @@ ___ia64_inl (unsigned long port)
        return ret;
 }
 
-static inline void
-___ia64_outb (unsigned char val, unsigned long port)
+#define outb outb
+static inline void outb(unsigned char val, unsigned long port)
 {
        volatile unsigned char *addr = __ia64_mk_io_addr(port);
 
@@ -198,8 +178,8 @@ ___ia64_outb (unsigned char val, unsigned long port)
        __ia64_mf_a();
 }
 
-static inline void
-___ia64_outw (unsigned short val, unsigned long port)
+#define outw outw
+static inline void outw(unsigned short val, unsigned long port)
 {
        volatile unsigned short *addr = __ia64_mk_io_addr(port);
 
@@ -207,8 +187,8 @@ ___ia64_outw (unsigned short val, unsigned long port)
        __ia64_mf_a();
 }
 
-static inline void
-___ia64_outl (unsigned int val, unsigned long port)
+#define outl outl
+static inline void outl(unsigned int val, unsigned long port)
 {
        volatile unsigned int *addr = __ia64_mk_io_addr(port);
 
@@ -216,199 +196,63 @@ ___ia64_outl (unsigned int val, unsigned long port)
        __ia64_mf_a();
 }
 
-static inline void
-__insb (unsigned long port, void *dst, unsigned long count)
+#define insb insb
+static inline void insb(unsigned long port, void *dst, unsigned long count)
 {
        unsigned char *dp = dst;
 
        while (count--)
-               *dp++ = platform_inb(port);
+               *dp++ = inb(port);
 }
 
-static inline void
-__insw (unsigned long port, void *dst, unsigned long count)
+#define insw insw
+static inline void insw(unsigned long port, void *dst, unsigned long count)
 {
        unsigned short *dp = dst;
 
        while (count--)
-               put_unaligned(platform_inw(port), dp++);
+               put_unaligned(inw(port), dp++);
 }
 
-static inline void
-__insl (unsigned long port, void *dst, unsigned long count)
+#define insl insl
+static inline void insl(unsigned long port, void *dst, unsigned long count)
 {
        unsigned int *dp = dst;
 
        while (count--)
-               put_unaligned(platform_inl(port), dp++);
+               put_unaligned(inl(port), dp++);
 }
 
-static inline void
-__outsb (unsigned long port, const void *src, unsigned long count)
+#define outsb outsb
+static inline void outsb(unsigned long port, const void *src,
+               unsigned long count)
 {
        const unsigned char *sp = src;
 
        while (count--)
-               platform_outb(*sp++, port);
+               outb(*sp++, port);
 }
 
-static inline void
-__outsw (unsigned long port, const void *src, unsigned long count)
+#define outsw outsw
+static inline void outsw(unsigned long port, const void *src,
+               unsigned long count)
 {
        const unsigned short *sp = src;
 
        while (count--)
-               platform_outw(get_unaligned(sp++), port);
+               outw(get_unaligned(sp++), port);
 }
 
-static inline void
-__outsl (unsigned long port, const void *src, unsigned long count)
+#define outsl outsl
+static inline void outsl(unsigned long port, const void *src,
+               unsigned long count)
 {
        const unsigned int *sp = src;
 
        while (count--)
-               platform_outl(get_unaligned(sp++), port);
+               outl(get_unaligned(sp++), port);
 }
 
-/*
- * Unfortunately, some platforms are broken and do not follow the IA-64 architecture
- * specification regarding legacy I/O support.  Thus, we have to make these operations
- * platform dependent...
- */
-#define __inb          platform_inb
-#define __inw          platform_inw
-#define __inl          platform_inl
-#define __outb         platform_outb
-#define __outw         platform_outw
-#define __outl         platform_outl
-
-#define inb(p)         __inb(p)
-#define inw(p)         __inw(p)
-#define inl(p)         __inl(p)
-#define insb(p,d,c)    __insb(p,d,c)
-#define insw(p,d,c)    __insw(p,d,c)
-#define insl(p,d,c)    __insl(p,d,c)
-#define outb(v,p)      __outb(v,p)
-#define outw(v,p)      __outw(v,p)
-#define outl(v,p)      __outl(v,p)
-#define outsb(p,s,c)   __outsb(p,s,c)
-#define outsw(p,s,c)   __outsw(p,s,c)
-#define outsl(p,s,c)   __outsl(p,s,c)
-
-/*
- * The address passed to these functions are ioremap()ped already.
- *
- * We need these to be machine vectors since some platforms don't provide
- * DMA coherence via PIO reads (PCI drivers and the spec imply that this is
- * a good idea).  Writes are ok though for all existing ia64 platforms (and
- * hopefully it'll stay that way).
- */
-static inline unsigned char
-___ia64_readb (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned char __force *)addr;
-}
-
-static inline unsigned short
-___ia64_readw (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned short __force *)addr;
-}
-
-static inline unsigned int
-___ia64_readl (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned int __force *) addr;
-}
-
-static inline unsigned long
-___ia64_readq (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned long __force *) addr;
-}
-
-static inline void
-__writeb (unsigned char val, volatile void __iomem *addr)
-{
-       *(volatile unsigned char __force *) addr = val;
-}
-
-static inline void
-__writew (unsigned short val, volatile void __iomem *addr)
-{
-       *(volatile unsigned short __force *) addr = val;
-}
-
-static inline void
-__writel (unsigned int val, volatile void __iomem *addr)
-{
-       *(volatile unsigned int __force *) addr = val;
-}
-
-static inline void
-__writeq (unsigned long val, volatile void __iomem *addr)
-{
-       *(volatile unsigned long __force *) addr = val;
-}
-
-#define __readb                platform_readb
-#define __readw                platform_readw
-#define __readl                platform_readl
-#define __readq                platform_readq
-#define __readb_relaxed        platform_readb_relaxed
-#define __readw_relaxed        platform_readw_relaxed
-#define __readl_relaxed        platform_readl_relaxed
-#define __readq_relaxed        platform_readq_relaxed
-
-#define readb(a)       __readb((a))
-#define readw(a)       __readw((a))
-#define readl(a)       __readl((a))
-#define readq(a)       __readq((a))
-#define readb_relaxed(a)       __readb_relaxed((a))
-#define readw_relaxed(a)       __readw_relaxed((a))
-#define readl_relaxed(a)       __readl_relaxed((a))
-#define readq_relaxed(a)       __readq_relaxed((a))
-#define __raw_readb    readb
-#define __raw_readw    readw
-#define __raw_readl    readl
-#define __raw_readq    readq
-#define __raw_readb_relaxed    readb_relaxed
-#define __raw_readw_relaxed    readw_relaxed
-#define __raw_readl_relaxed    readl_relaxed
-#define __raw_readq_relaxed    readq_relaxed
-#define writeb(v,a)    __writeb((v), (a))
-#define writew(v,a)    __writew((v), (a))
-#define writel(v,a)    __writel((v), (a))
-#define writeq(v,a)    __writeq((v), (a))
-#define writeb_relaxed(v,a)    __writeb((v), (a))
-#define writew_relaxed(v,a)    __writew((v), (a))
-#define writel_relaxed(v,a)    __writel((v), (a))
-#define writeq_relaxed(v,a)    __writeq((v), (a))
-#define __raw_writeb   writeb
-#define __raw_writew   writew
-#define __raw_writel   writel
-#define __raw_writeq   writeq
-
-#ifndef inb_p
-# define inb_p         inb
-#endif
-#ifndef inw_p
-# define inw_p         inw
-#endif
-#ifndef inl_p
-# define inl_p         inl
-#endif
-
-#ifndef outb_p
-# define outb_p                outb
-#endif
-#ifndef outw_p
-# define outw_p                outw
-#endif
-#ifndef outl_p
-# define outl_p                outl
-#endif
-
 # ifdef __KERNEL__
 
 extern void __iomem * ioremap(unsigned long offset, unsigned long size);
index 7429a72..7904f59 100644 (file)
@@ -8,13 +8,10 @@
 extern void no_iommu_init(void);
 #ifdef CONFIG_INTEL_IOMMU
 extern int force_iommu, no_iommu;
-extern int iommu_pass_through;
 extern int iommu_detected;
 #else
-#define iommu_pass_through     (0)
 #define no_iommu               (1)
 #define iommu_detected         (0)
 #endif
-extern void machvec_init(const char *name);
 
 #endif
index f48556c..a91aeb4 100644 (file)
@@ -52,8 +52,6 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_IOSAPIC
-
 #define NR_IOSAPICS                    256
 
 #define iosapic_pcat_compat_init       ia64_native_iosapic_pcat_compat_init
@@ -103,16 +101,6 @@ extern int __init iosapic_register_platform_intr (u32 int_type,
 #ifdef CONFIG_NUMA
 extern void map_iosapic_to_node (unsigned int, int);
 #endif
-#else
-#define iosapic_system_init(pcat_compat)                       do { } while (0)
-#define iosapic_init(address,gsi_base)                         (-EINVAL)
-#define iosapic_remove(gsi_base)                               (-ENODEV)
-#define iosapic_register_intr(gsi,polarity,trigger)            (gsi)
-#define iosapic_unregister_intr(irq)                           do { } while (0)
-#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)
-#define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \
-       polarity,trigger)                                       (gsi)
-#endif
 
 # endif /* !__ASSEMBLY__ */
 #endif /* __ASM_IA64_IOSAPIC_H */
index 8b84a55..5acf52e 100644 (file)
@@ -28,9 +28,6 @@ irq_canonicalize (int irq)
 }
 
 extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
-bool is_affinity_mask_valid(const struct cpumask *cpumask);
-
-#define is_affinity_mask_valid is_affinity_mask_valid
 
 int create_irq(void);
 void destroy_irq(unsigned int irq);
diff --git a/arch/ia64/include/asm/machvec.h b/arch/ia64/include/asm/machvec.h
deleted file mode 100644 (file)
index beae261..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Machine vector for IA-64.
- *
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
- * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
- * Copyright (C) 1999-2001, 2003-2004 Hewlett-Packard Co.
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- */
-#ifndef _ASM_IA64_MACHVEC_H
-#define _ASM_IA64_MACHVEC_H
-
-#include <linux/types.h>
-
-/* forward declarations: */
-struct device;
-struct pt_regs;
-struct scatterlist;
-struct page;
-struct mm_struct;
-struct pci_bus;
-struct task_struct;
-struct pci_dev;
-struct msi_desc;
-
-typedef void ia64_mv_setup_t (char **);
-typedef void ia64_mv_cpu_init_t (void);
-typedef void ia64_mv_irq_init_t (void);
-typedef void ia64_mv_send_ipi_t (int, int, int, int);
-typedef void ia64_mv_timer_interrupt_t (int, void *);
-typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long);
-typedef u8 ia64_mv_irq_to_vector (int);
-typedef unsigned int ia64_mv_local_vector_to_irq (u8);
-typedef char *ia64_mv_pci_get_legacy_mem_t (struct pci_bus *);
-typedef int ia64_mv_pci_legacy_read_t (struct pci_bus *, u16 port, u32 *val,
-                                      u8 size);
-typedef int ia64_mv_pci_legacy_write_t (struct pci_bus *, u16 port, u32 val,
-                                       u8 size);
-typedef void ia64_mv_migrate_t(struct task_struct * task);
-typedef void ia64_mv_pci_fixup_bus_t (struct pci_bus *);
-typedef void ia64_mv_kernel_launch_event_t(void);
-
-/* DMA-mapping interface: */
-typedef void ia64_mv_dma_init (void);
-typedef const struct dma_map_ops *ia64_mv_dma_get_ops(struct device *);
-
-/*
- * WARNING: The legacy I/O space is _architected_.  Platforms are
- * expected to follow this architected model (see Section 10.7 in the
- * IA-64 Architecture Software Developer's Manual).  Unfortunately,
- * some broken machines do not follow that model, which is why we have
- * to make the inX/outX operations part of the machine vector.
- * Platform designers should follow the architected model whenever
- * possible.
- */
-typedef unsigned int ia64_mv_inb_t (unsigned long);
-typedef unsigned int ia64_mv_inw_t (unsigned long);
-typedef unsigned int ia64_mv_inl_t (unsigned long);
-typedef void ia64_mv_outb_t (unsigned char, unsigned long);
-typedef void ia64_mv_outw_t (unsigned short, unsigned long);
-typedef void ia64_mv_outl_t (unsigned int, unsigned long);
-typedef void ia64_mv_mmiowb_t (void);
-typedef unsigned char ia64_mv_readb_t (const volatile void __iomem *);
-typedef unsigned short ia64_mv_readw_t (const volatile void __iomem *);
-typedef unsigned int ia64_mv_readl_t (const volatile void __iomem *);
-typedef unsigned long ia64_mv_readq_t (const volatile void __iomem *);
-typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *);
-typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
-typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
-typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
-
-typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
-typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
-
-static inline void
-machvec_noop (void)
-{
-}
-
-static inline void
-machvec_noop_task (struct task_struct *task)
-{
-}
-
-static inline void
-machvec_noop_bus (struct pci_bus *bus)
-{
-}
-
-extern void machvec_setup (char **);
-extern void machvec_timer_interrupt (int, void *);
-
-# if defined (CONFIG_IA64_HP_SIM)
-#  include <asm/machvec_hpsim.h>
-# elif defined (CONFIG_IA64_DIG)
-#  include <asm/machvec_dig.h>
-# elif defined(CONFIG_IA64_DIG_VTD)
-#  include <asm/machvec_dig_vtd.h>
-# elif defined (CONFIG_IA64_HP_ZX1)
-#  include <asm/machvec_hpzx1.h>
-# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB)
-#  include <asm/machvec_hpzx1_swiotlb.h>
-# elif defined (CONFIG_IA64_SGI_SN2)
-#  include <asm/machvec_sn2.h>
-# elif defined (CONFIG_IA64_SGI_UV)
-#  include <asm/machvec_uv.h>
-# elif defined (CONFIG_IA64_GENERIC)
-
-# ifdef MACHVEC_PLATFORM_HEADER
-#  include MACHVEC_PLATFORM_HEADER
-# else
-#  define ia64_platform_name   ia64_mv.name
-#  define platform_setup       ia64_mv.setup
-#  define platform_cpu_init    ia64_mv.cpu_init
-#  define platform_irq_init    ia64_mv.irq_init
-#  define platform_send_ipi    ia64_mv.send_ipi
-#  define platform_timer_interrupt     ia64_mv.timer_interrupt
-#  define platform_global_tlb_purge    ia64_mv.global_tlb_purge
-#  define platform_dma_init            ia64_mv.dma_init
-#  define platform_dma_get_ops         ia64_mv.dma_get_ops
-#  define platform_irq_to_vector       ia64_mv.irq_to_vector
-#  define platform_local_vector_to_irq ia64_mv.local_vector_to_irq
-#  define platform_pci_get_legacy_mem  ia64_mv.pci_get_legacy_mem
-#  define platform_pci_legacy_read     ia64_mv.pci_legacy_read
-#  define platform_pci_legacy_write    ia64_mv.pci_legacy_write
-#  define platform_inb         ia64_mv.inb
-#  define platform_inw         ia64_mv.inw
-#  define platform_inl         ia64_mv.inl
-#  define platform_outb                ia64_mv.outb
-#  define platform_outw                ia64_mv.outw
-#  define platform_outl                ia64_mv.outl
-#  define platform_mmiowb      ia64_mv.mmiowb
-#  define platform_readb        ia64_mv.readb
-#  define platform_readw        ia64_mv.readw
-#  define platform_readl        ia64_mv.readl
-#  define platform_readq        ia64_mv.readq
-#  define platform_readb_relaxed        ia64_mv.readb_relaxed
-#  define platform_readw_relaxed        ia64_mv.readw_relaxed
-#  define platform_readl_relaxed        ia64_mv.readl_relaxed
-#  define platform_readq_relaxed        ia64_mv.readq_relaxed
-#  define platform_migrate             ia64_mv.migrate
-#  define platform_setup_msi_irq       ia64_mv.setup_msi_irq
-#  define platform_teardown_msi_irq    ia64_mv.teardown_msi_irq
-#  define platform_pci_fixup_bus       ia64_mv.pci_fixup_bus
-#  define platform_kernel_launch_event ia64_mv.kernel_launch_event
-# endif
-
-/* __attribute__((__aligned__(16))) is required to make size of the
- * structure multiple of 16 bytes.
- * This will fillup the holes created because of section 3.3.1 in
- * Software Conventions guide.
- */
-struct ia64_machine_vector {
-       const char *name;
-       ia64_mv_setup_t *setup;
-       ia64_mv_cpu_init_t *cpu_init;
-       ia64_mv_irq_init_t *irq_init;
-       ia64_mv_send_ipi_t *send_ipi;
-       ia64_mv_timer_interrupt_t *timer_interrupt;
-       ia64_mv_global_tlb_purge_t *global_tlb_purge;
-       ia64_mv_dma_init *dma_init;
-       ia64_mv_dma_get_ops *dma_get_ops;
-       ia64_mv_irq_to_vector *irq_to_vector;
-       ia64_mv_local_vector_to_irq *local_vector_to_irq;
-       ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem;
-       ia64_mv_pci_legacy_read_t *pci_legacy_read;
-       ia64_mv_pci_legacy_write_t *pci_legacy_write;
-       ia64_mv_inb_t *inb;
-       ia64_mv_inw_t *inw;
-       ia64_mv_inl_t *inl;
-       ia64_mv_outb_t *outb;
-       ia64_mv_outw_t *outw;
-       ia64_mv_outl_t *outl;
-       ia64_mv_mmiowb_t *mmiowb;
-       ia64_mv_readb_t *readb;
-       ia64_mv_readw_t *readw;
-       ia64_mv_readl_t *readl;
-       ia64_mv_readq_t *readq;
-       ia64_mv_readb_relaxed_t *readb_relaxed;
-       ia64_mv_readw_relaxed_t *readw_relaxed;
-       ia64_mv_readl_relaxed_t *readl_relaxed;
-       ia64_mv_readq_relaxed_t *readq_relaxed;
-       ia64_mv_migrate_t *migrate;
-       ia64_mv_setup_msi_irq_t *setup_msi_irq;
-       ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
-       ia64_mv_pci_fixup_bus_t *pci_fixup_bus;
-       ia64_mv_kernel_launch_event_t *kernel_launch_event;
-} __attribute__((__aligned__(16))); /* align attrib? see above comment */
-
-#define MACHVEC_INIT(name)                     \
-{                                              \
-       #name,                                  \
-       platform_setup,                         \
-       platform_cpu_init,                      \
-       platform_irq_init,                      \
-       platform_send_ipi,                      \
-       platform_timer_interrupt,               \
-       platform_global_tlb_purge,              \
-       platform_dma_init,                      \
-       platform_dma_get_ops,                   \
-       platform_irq_to_vector,                 \
-       platform_local_vector_to_irq,           \
-       platform_pci_get_legacy_mem,            \
-       platform_pci_legacy_read,               \
-       platform_pci_legacy_write,              \
-       platform_inb,                           \
-       platform_inw,                           \
-       platform_inl,                           \
-       platform_outb,                          \
-       platform_outw,                          \
-       platform_outl,                          \
-       platform_mmiowb,                        \
-       platform_readb,                         \
-       platform_readw,                         \
-       platform_readl,                         \
-       platform_readq,                         \
-       platform_readb_relaxed,                 \
-       platform_readw_relaxed,                 \
-       platform_readl_relaxed,                 \
-       platform_readq_relaxed,                 \
-       platform_migrate,                       \
-       platform_setup_msi_irq,                 \
-       platform_teardown_msi_irq,              \
-       platform_pci_fixup_bus,                 \
-       platform_kernel_launch_event            \
-}
-
-extern struct ia64_machine_vector ia64_mv;
-extern void machvec_init (const char *name);
-extern void machvec_init_from_cmdline(const char *cmdline);
-
-# else
-#  error Unknown configuration.  Update arch/ia64/include/asm/machvec.h.
-# endif /* CONFIG_IA64_GENERIC */
-
-extern void swiotlb_dma_init(void);
-extern const struct dma_map_ops *dma_get_ops(struct device *);
-
-/*
- * Define default versions so we can extend machvec for new platforms without having
- * to update the machvec files for all existing platforms.
- */
-#ifndef platform_setup
-# define platform_setup                        machvec_setup
-#endif
-#ifndef platform_cpu_init
-# define platform_cpu_init             machvec_noop
-#endif
-#ifndef platform_irq_init
-# define platform_irq_init             machvec_noop
-#endif
-
-#ifndef platform_send_ipi
-# define platform_send_ipi             ia64_send_ipi   /* default to architected version */
-#endif
-#ifndef platform_timer_interrupt
-# define platform_timer_interrupt      machvec_timer_interrupt
-#endif
-#ifndef platform_global_tlb_purge
-# define platform_global_tlb_purge     ia64_global_tlb_purge /* default to architected version */
-#endif
-#ifndef platform_kernel_launch_event
-# define platform_kernel_launch_event  machvec_noop
-#endif
-#ifndef platform_dma_init
-# define platform_dma_init             swiotlb_dma_init
-#endif
-#ifndef platform_dma_get_ops
-# define platform_dma_get_ops          dma_get_ops
-#endif
-#ifndef platform_irq_to_vector
-# define platform_irq_to_vector                __ia64_irq_to_vector
-#endif
-#ifndef platform_local_vector_to_irq
-# define platform_local_vector_to_irq  __ia64_local_vector_to_irq
-#endif
-#ifndef platform_pci_get_legacy_mem
-# define platform_pci_get_legacy_mem   ia64_pci_get_legacy_mem
-#endif
-#ifndef platform_pci_legacy_read
-# define platform_pci_legacy_read      ia64_pci_legacy_read
-extern int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size);
-#endif
-#ifndef platform_pci_legacy_write
-# define platform_pci_legacy_write     ia64_pci_legacy_write
-extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size);
-#endif
-#ifndef platform_inb
-# define platform_inb          __ia64_inb
-#endif
-#ifndef platform_inw
-# define platform_inw          __ia64_inw
-#endif
-#ifndef platform_inl
-# define platform_inl          __ia64_inl
-#endif
-#ifndef platform_outb
-# define platform_outb         __ia64_outb
-#endif
-#ifndef platform_outw
-# define platform_outw         __ia64_outw
-#endif
-#ifndef platform_outl
-# define platform_outl         __ia64_outl
-#endif
-#ifndef platform_mmiowb
-# define platform_mmiowb       __ia64_mmiowb
-#endif
-#ifndef platform_readb
-# define platform_readb                __ia64_readb
-#endif
-#ifndef platform_readw
-# define platform_readw                __ia64_readw
-#endif
-#ifndef platform_readl
-# define platform_readl                __ia64_readl
-#endif
-#ifndef platform_readq
-# define platform_readq                __ia64_readq
-#endif
-#ifndef platform_readb_relaxed
-# define platform_readb_relaxed        __ia64_readb_relaxed
-#endif
-#ifndef platform_readw_relaxed
-# define platform_readw_relaxed        __ia64_readw_relaxed
-#endif
-#ifndef platform_readl_relaxed
-# define platform_readl_relaxed        __ia64_readl_relaxed
-#endif
-#ifndef platform_readq_relaxed
-# define platform_readq_relaxed        __ia64_readq_relaxed
-#endif
-#ifndef platform_migrate
-# define platform_migrate machvec_noop_task
-#endif
-#ifndef platform_setup_msi_irq
-# define platform_setup_msi_irq                ((ia64_mv_setup_msi_irq_t*)NULL)
-#endif
-#ifndef platform_teardown_msi_irq
-# define platform_teardown_msi_irq     ((ia64_mv_teardown_msi_irq_t*)NULL)
-#endif
-#ifndef platform_pci_fixup_bus
-# define platform_pci_fixup_bus        machvec_noop_bus
-#endif
-
-#endif /* _ASM_IA64_MACHVEC_H */
diff --git a/arch/ia64/include/asm/machvec_dig.h b/arch/ia64/include/asm/machvec_dig.h
deleted file mode 100644 (file)
index bc230f6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_IA64_MACHVEC_DIG_h
-#define _ASM_IA64_MACHVEC_DIG_h
-
-extern ia64_mv_setup_t dig_setup;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name     "dig"
-#define platform_setup         dig_setup
-
-#endif /* _ASM_IA64_MACHVEC_DIG_h */
diff --git a/arch/ia64/include/asm/machvec_dig_vtd.h b/arch/ia64/include/asm/machvec_dig_vtd.h
deleted file mode 100644 (file)
index bb44eb9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_IA64_MACHVEC_DIG_VTD_h
-#define _ASM_IA64_MACHVEC_DIG_VTD_h
-
-extern ia64_mv_setup_t                 dig_setup;
-extern ia64_mv_dma_init                        pci_iommu_alloc;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name                     "dig_vtd"
-#define platform_setup                         dig_setup
-#define platform_dma_init                      pci_iommu_alloc
-
-#endif /* _ASM_IA64_MACHVEC_DIG_VTD_h */
diff --git a/arch/ia64/include/asm/machvec_hpsim.h b/arch/ia64/include/asm/machvec_hpsim.h
deleted file mode 100644 (file)
index 056f840..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_IA64_MACHVEC_HPSIM_h
-#define _ASM_IA64_MACHVEC_HPSIM_h
-
-extern ia64_mv_setup_t hpsim_setup;
-extern ia64_mv_irq_init_t hpsim_irq_init;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name     "hpsim"
-#define platform_setup         hpsim_setup
-#define platform_irq_init      hpsim_irq_init
-
-#endif /* _ASM_IA64_MACHVEC_HPSIM_h */
diff --git a/arch/ia64/include/asm/machvec_hpzx1.h b/arch/ia64/include/asm/machvec_hpzx1.h
deleted file mode 100644 (file)
index 5299ac3..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_IA64_MACHVEC_HPZX1_h
-#define _ASM_IA64_MACHVEC_HPZX1_h
-
-extern ia64_mv_setup_t                 dig_setup;
-extern ia64_mv_dma_init                        sba_dma_init;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name                     "hpzx1"
-#define platform_setup                         dig_setup
-#define platform_dma_init                      sba_dma_init
-
-#endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff --git a/arch/ia64/include/asm/machvec_hpzx1_swiotlb.h b/arch/ia64/include/asm/machvec_hpzx1_swiotlb.h
deleted file mode 100644 (file)
index 5aec6a0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h
-#define _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h
-
-extern ia64_mv_setup_t                         dig_setup;
-extern ia64_mv_dma_get_ops                     hwsw_dma_get_ops;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name                     "hpzx1_swiotlb"
-#define platform_setup                         dig_setup
-#define platform_dma_init                      machvec_noop
-#define platform_dma_get_ops                   hwsw_dma_get_ops
-
-#endif /* _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h */
diff --git a/arch/ia64/include/asm/machvec_init.h b/arch/ia64/include/asm/machvec_init.h
deleted file mode 100644 (file)
index 2aafb69..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <asm/iommu.h>
-#include <asm/machvec.h>
-
-extern ia64_mv_send_ipi_t ia64_send_ipi;
-extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge;
-extern ia64_mv_irq_to_vector __ia64_irq_to_vector;
-extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq;
-extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem;
-extern ia64_mv_pci_legacy_read_t ia64_pci_legacy_read;
-extern ia64_mv_pci_legacy_write_t ia64_pci_legacy_write;
-
-extern ia64_mv_inb_t __ia64_inb;
-extern ia64_mv_inw_t __ia64_inw;
-extern ia64_mv_inl_t __ia64_inl;
-extern ia64_mv_outb_t __ia64_outb;
-extern ia64_mv_outw_t __ia64_outw;
-extern ia64_mv_outl_t __ia64_outl;
-extern ia64_mv_mmiowb_t __ia64_mmiowb;
-extern ia64_mv_readb_t __ia64_readb;
-extern ia64_mv_readw_t __ia64_readw;
-extern ia64_mv_readl_t __ia64_readl;
-extern ia64_mv_readq_t __ia64_readq;
-extern ia64_mv_readb_t __ia64_readb_relaxed;
-extern ia64_mv_readw_t __ia64_readw_relaxed;
-extern ia64_mv_readl_t __ia64_readl_relaxed;
-extern ia64_mv_readq_t __ia64_readq_relaxed;
-
-#define MACHVEC_HELPER(name)                                                                   \
- struct ia64_machine_vector machvec_##name __attribute__ ((unused, __section__ (".machvec")))  \
-       = MACHVEC_INIT(name);
-
-#define MACHVEC_DEFINE(name)   MACHVEC_HELPER(name)
-
-MACHVEC_DEFINE(MACHVEC_PLATFORM_NAME)
diff --git a/arch/ia64/include/asm/machvec_sn2.h b/arch/ia64/include/asm/machvec_sn2.h
deleted file mode 100644 (file)
index a243e4f..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2002-2003,2006 Silicon Graphics, Inc.  All Rights Reserved.
- * 
- * This program is free software; you can redistribute it and/or modify it 
- * under the terms of version 2 of the GNU General Public License 
- * as published by the Free Software Foundation.
- * 
- * This program is distributed in the hope that it would be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
- * 
- * Further, this software is distributed without any warranty that it is 
- * free of the rightful claim of any third person regarding infringement 
- * or the like.  Any license provided herein, whether implied or 
- * otherwise, applies only to this software file.  Patent licenses, if 
- * any, provided herein do not apply to combinations of this program with 
- * other software, or any other product whatsoever.
- * 
- * You should have received a copy of the GNU General Public 
- * License along with this program; if not, write the Free Software 
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- * 
- * For further information regarding this notice, see: 
- * 
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#ifndef _ASM_IA64_MACHVEC_SN2_H
-#define _ASM_IA64_MACHVEC_SN2_H
-
-extern ia64_mv_setup_t sn_setup;
-extern ia64_mv_cpu_init_t sn_cpu_init;
-extern ia64_mv_irq_init_t sn_irq_init;
-extern ia64_mv_send_ipi_t sn2_send_IPI;
-extern ia64_mv_timer_interrupt_t sn_timer_interrupt;
-extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge;
-extern ia64_mv_irq_to_vector sn_irq_to_vector;
-extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq;
-extern ia64_mv_pci_get_legacy_mem_t sn_pci_get_legacy_mem;
-extern ia64_mv_pci_legacy_read_t sn_pci_legacy_read;
-extern ia64_mv_pci_legacy_write_t sn_pci_legacy_write;
-extern ia64_mv_inb_t __sn_inb;
-extern ia64_mv_inw_t __sn_inw;
-extern ia64_mv_inl_t __sn_inl;
-extern ia64_mv_outb_t __sn_outb;
-extern ia64_mv_outw_t __sn_outw;
-extern ia64_mv_outl_t __sn_outl;
-extern ia64_mv_mmiowb_t __sn_mmiowb;
-extern ia64_mv_readb_t __sn_readb;
-extern ia64_mv_readw_t __sn_readw;
-extern ia64_mv_readl_t __sn_readl;
-extern ia64_mv_readq_t __sn_readq;
-extern ia64_mv_readb_t __sn_readb_relaxed;
-extern ia64_mv_readw_t __sn_readw_relaxed;
-extern ia64_mv_readl_t __sn_readl_relaxed;
-extern ia64_mv_readq_t __sn_readq_relaxed;
-extern ia64_mv_dma_init                        sn_dma_init;
-extern ia64_mv_migrate_t               sn_migrate;
-extern ia64_mv_kernel_launch_event_t   sn_kernel_launch_event;
-extern ia64_mv_setup_msi_irq_t         sn_setup_msi_irq;
-extern ia64_mv_teardown_msi_irq_t      sn_teardown_msi_irq;
-extern ia64_mv_pci_fixup_bus_t         sn_pci_fixup_bus;
-
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name             "sn2"
-#define platform_setup                 sn_setup
-#define platform_cpu_init              sn_cpu_init
-#define platform_irq_init              sn_irq_init
-#define platform_send_ipi              sn2_send_IPI
-#define platform_timer_interrupt       sn_timer_interrupt
-#define platform_global_tlb_purge       sn2_global_tlb_purge
-#define platform_pci_fixup             sn_pci_fixup
-#define platform_inb                   __sn_inb
-#define platform_inw                   __sn_inw
-#define platform_inl                   __sn_inl
-#define platform_outb                  __sn_outb
-#define platform_outw                  __sn_outw
-#define platform_outl                  __sn_outl
-#define platform_mmiowb                        __sn_mmiowb
-#define platform_readb                 __sn_readb
-#define platform_readw                 __sn_readw
-#define platform_readl                 __sn_readl
-#define platform_readq                 __sn_readq
-#define platform_readb_relaxed         __sn_readb_relaxed
-#define platform_readw_relaxed         __sn_readw_relaxed
-#define platform_readl_relaxed         __sn_readl_relaxed
-#define platform_readq_relaxed         __sn_readq_relaxed
-#define platform_irq_to_vector         sn_irq_to_vector
-#define platform_local_vector_to_irq   sn_local_vector_to_irq
-#define platform_pci_get_legacy_mem    sn_pci_get_legacy_mem
-#define platform_pci_legacy_read       sn_pci_legacy_read
-#define platform_pci_legacy_write      sn_pci_legacy_write
-#define platform_dma_init              sn_dma_init
-#define platform_migrate               sn_migrate
-#define platform_kernel_launch_event    sn_kernel_launch_event
-#ifdef CONFIG_PCI_MSI
-#define platform_setup_msi_irq         sn_setup_msi_irq
-#define platform_teardown_msi_irq      sn_teardown_msi_irq
-#else
-#define platform_setup_msi_irq         ((ia64_mv_setup_msi_irq_t*)NULL)
-#define platform_teardown_msi_irq      ((ia64_mv_teardown_msi_irq_t*)NULL)
-#endif
-#define platform_pci_fixup_bus         sn_pci_fixup_bus
-
-#include <asm/sn/io.h>
-
-#endif /* _ASM_IA64_MACHVEC_SN2_H */
diff --git a/arch/ia64/include/asm/machvec_uv.h b/arch/ia64/include/asm/machvec_uv.h
deleted file mode 100644 (file)
index 2c50853..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * SGI UV Core Functions
- *
- * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_MACHVEC_UV_H
-#define _ASM_IA64_MACHVEC_UV_H
-
-extern ia64_mv_setup_t uv_setup;
-
-/*
- * This stuff has dual use!
- *
- * For a generic kernel, the macros are used to initialize the
- * platform's machvec structure.  When compiling a non-generic kernel,
- * the macros are used directly.
- */
-#define ia64_platform_name             "uv"
-#define platform_setup                 uv_setup
-
-#endif /* _ASM_IA64_MACHVEC_UV_H */
index 297b85a..d67aab4 100644 (file)
@@ -3,22 +3,14 @@
 #ifndef _ASM_IA64_MMIOWB_H
 #define _ASM_IA64_MMIOWB_H
 
-#include <asm/machvec.h>
-
 /**
- * ___ia64_mmiowb - I/O write barrier
+ * mmiowb - I/O write barrier
  *
  * Ensure ordering of I/O space writes.  This will make sure that writes
  * following the barrier will arrive after all previous writes.  For most
  * ia64 platforms, this is a simple 'mf.a' instruction.
  */
-static inline void ___ia64_mmiowb(void)
-{
-       ia64_mfa();
-}
-
-#define __ia64_mmiowb  ___ia64_mmiowb
-#define mmiowb()       platform_mmiowb()
+#define mmiowb()       ia64_mfa()
 
 #include <asm-generic/mmiowb.h>
 
index e0de617..767201f 100644 (file)
@@ -27,16 +27,9 @@ static inline int pfn_to_nid(unsigned long pfn)
                return nid;
 }
 
-#ifdef CONFIG_IA64_DIG /* DIG systems are small */
-# define MAX_PHYSNODE_ID       8
-# define NR_NODE_MEMBLKS       (MAX_NUMNODES * 8)
-#else /* sn2 is the biggest case, so we use that if !DIG */
-# define MAX_PHYSNODE_ID       2048
-# define NR_NODE_MEMBLKS       (MAX_NUMNODES * 4)
-#endif
-
-#else /* CONFIG_NUMA */
-# define NR_NODE_MEMBLKS       (MAX_NUMNODES * 4)
+#define MAX_PHYSNODE_ID                2048
 #endif /* CONFIG_NUMA */
 
+#define NR_NODE_MEMBLKS                (MAX_NUMNODES * 4)
+
 #endif /* _ASM_IA64_MMZONE_H */
index 780e874..8c163d1 100644 (file)
@@ -39,9 +39,9 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
                                      struct vm_area_struct *vma,
                                      enum pci_mmap_state mmap_state);
 
-#define pci_get_legacy_mem platform_pci_get_legacy_mem
-#define pci_legacy_read platform_pci_legacy_read
-#define pci_legacy_write platform_pci_legacy_write
+char *pci_get_legacy_mem(struct pci_bus *bus);
+int pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size);
+int pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size);
 
 struct pci_controller {
        struct acpi_device *companion;
@@ -69,7 +69,4 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
        return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14);
 }
 
-#ifdef CONFIG_INTEL_IOMMU
-extern void pci_iommu_alloc(void);
-#endif
 #endif /* _ASM_IA64_PCI_H */
index c91ef98..95a2ec3 100644 (file)
@@ -679,8 +679,6 @@ enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT,
 
 void default_idle(void);
 
-#define ia64_platform_is(x) (strcmp(x, ia64_platform_name) == 0)
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_IA64_PROCESSOR_H */
diff --git a/arch/ia64/include/asm/sn/acpi.h b/arch/ia64/include/asm/sn/acpi.h
deleted file mode 100644 (file)
index fd480db..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_ACPI_H
-#define _ASM_IA64_SN_ACPI_H
-
-extern int sn_acpi_rev;
-#define SN_ACPI_BASE_SUPPORT()   (sn_acpi_rev >= 0x20101)
-
-#endif /* _ASM_IA64_SN_ACPI_H */
diff --git a/arch/ia64/include/asm/sn/addrs.h b/arch/ia64/include/asm/sn/addrs.h
deleted file mode 100644 (file)
index e715c79..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 1992-1999,2001-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_ADDRS_H
-#define _ASM_IA64_SN_ADDRS_H
-
-#include <asm/percpu.h>
-#include <asm/sn/types.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/pda.h>
-
-/*
- *  Memory/SHUB Address Format:
- *  +-+---------+--+--------------+
- *  |0|  NASID  |AS| NodeOffset   |
- *  +-+---------+--+--------------+
- *
- *  NASID: (low NASID bit is 0) Memory and SHUB MMRs
- *   AS: 2-bit Address Space Identifier. Used only if low NASID bit is 0
- *     00: Local Resources and MMR space
- *           Top bit of NodeOffset
- *               0: Local resources space
- *                  node id:
- *                        0: IA64/NT compatibility space
- *                        2: Local MMR Space
- *                        4: Local memory, regardless of local node id
- *               1: Global MMR space
- *     01: GET space.
- *     10: AMO space.
- *     11: Cacheable memory space.
- *
- *   NodeOffset: byte offset
- *
- *
- *  TIO address format:
- *  +-+----------+--+--------------+
- *  |0|  NASID   |AS| Nodeoffset   |
- *  +-+----------+--+--------------+
- *
- *  NASID: (low NASID bit is 1) TIO
- *   AS: 2-bit Chiplet Identifier
- *     00: TIO LB (Indicates TIO MMR access.)
- *     01: TIO ICE (indicates coretalk space access.)
- * 
- *   NodeOffset: top bit must be set.
- *
- *
- * Note that in both of the above address formats, the low
- * NASID bit indicates if the reference is to the SHUB or TIO MMRs.
- */
-
-
-/*
- * Define basic shift & mask constants for manipulating NASIDs and AS values.
- */
-#define NASID_BITMASK          (sn_hub_info->nasid_bitmask)
-#define NASID_SHIFT            (sn_hub_info->nasid_shift)
-#define AS_SHIFT               (sn_hub_info->as_shift)
-#define AS_BITMASK             0x3UL
-
-#define NASID_MASK              ((u64)NASID_BITMASK << NASID_SHIFT)
-#define AS_MASK                        ((u64)AS_BITMASK << AS_SHIFT)
-
-
-/*
- * AS values. These are the same on both SHUB1 & SHUB2.
- */
-#define AS_GET_VAL             1UL
-#define AS_AMO_VAL             2UL
-#define AS_CAC_VAL             3UL
-#define AS_GET_SPACE           (AS_GET_VAL << AS_SHIFT)
-#define AS_AMO_SPACE           (AS_AMO_VAL << AS_SHIFT)
-#define AS_CAC_SPACE           (AS_CAC_VAL << AS_SHIFT)
-
-
-/* 
- * Virtual Mode Local & Global MMR space.  
- */
-#define SH1_LOCAL_MMR_OFFSET   0x8000000000UL
-#define SH2_LOCAL_MMR_OFFSET   0x0200000000UL
-#define LOCAL_MMR_OFFSET       (is_shub2() ? SH2_LOCAL_MMR_OFFSET : SH1_LOCAL_MMR_OFFSET)
-#define LOCAL_MMR_SPACE                (__IA64_UNCACHED_OFFSET | LOCAL_MMR_OFFSET)
-#define LOCAL_PHYS_MMR_SPACE   (RGN_BASE(RGN_HPAGE) | LOCAL_MMR_OFFSET)
-
-#define SH1_GLOBAL_MMR_OFFSET  0x0800000000UL
-#define SH2_GLOBAL_MMR_OFFSET  0x0300000000UL
-#define GLOBAL_MMR_OFFSET      (is_shub2() ? SH2_GLOBAL_MMR_OFFSET : SH1_GLOBAL_MMR_OFFSET)
-#define GLOBAL_MMR_SPACE       (__IA64_UNCACHED_OFFSET | GLOBAL_MMR_OFFSET)
-
-/*
- * Physical mode addresses
- */
-#define GLOBAL_PHYS_MMR_SPACE  (RGN_BASE(RGN_HPAGE) | GLOBAL_MMR_OFFSET)
-
-
-/*
- * Clear region & AS bits.
- */
-#define TO_PHYS_MASK           (~(RGN_BITS | AS_MASK))
-
-
-/*
- * Misc NASID manipulation.
- */
-#define NASID_SPACE(n)         ((u64)(n) << NASID_SHIFT)
-#define REMOTE_ADDR(n,a)       (NASID_SPACE(n) | (a))
-#define NODE_OFFSET(x)         ((x) & (NODE_ADDRSPACE_SIZE - 1))
-#define NODE_ADDRSPACE_SIZE     (1UL << AS_SHIFT)
-#define NASID_GET(x)           (int) (((u64) (x) >> NASID_SHIFT) & NASID_BITMASK)
-#define LOCAL_MMR_ADDR(a)      (LOCAL_MMR_SPACE | (a))
-#define GLOBAL_MMR_ADDR(n,a)   (GLOBAL_MMR_SPACE | REMOTE_ADDR(n,a))
-#define GLOBAL_MMR_PHYS_ADDR(n,a) (GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a))
-#define GLOBAL_CAC_ADDR(n,a)   (CAC_BASE | REMOTE_ADDR(n,a))
-#define CHANGE_NASID(n,x)      ((void *)(((u64)(x) & ~NASID_MASK) | NASID_SPACE(n)))
-#define IS_TIO_NASID(n)                ((n) & 1)
-
-
-/* non-II mmr's start at top of big window space (4G) */
-#define BWIN_TOP               0x0000000100000000UL
-
-/*
- * general address defines
- */
-#define CAC_BASE               (PAGE_OFFSET | AS_CAC_SPACE)
-#define AMO_BASE               (__IA64_UNCACHED_OFFSET | AS_AMO_SPACE)
-#define AMO_PHYS_BASE          (RGN_BASE(RGN_HPAGE) | AS_AMO_SPACE)
-#define GET_BASE               (PAGE_OFFSET | AS_GET_SPACE)
-
-/*
- * Convert Memory addresses between various addressing modes.
- */
-#define TO_PHYS(x)             (TO_PHYS_MASK & (x))
-#define TO_CAC(x)              (CAC_BASE     | TO_PHYS(x))
-#ifdef CONFIG_SGI_SN
-#define TO_AMO(x)              (AMO_BASE     | TO_PHYS(x))
-#define TO_GET(x)              (GET_BASE     | TO_PHYS(x))
-#else
-#define TO_AMO(x)              ({ BUG(); x; })
-#define TO_GET(x)              ({ BUG(); x; })
-#endif
-
-/*
- * Covert from processor physical address to II/TIO physical address:
- *     II - squeeze out the AS bits
- *     TIO- requires a chiplet id in bits 38-39.  For DMA to memory,
- *           the chiplet id is zero.  If we implement TIO-TIO dma, we might need
- *           to insert a chiplet id into this macro.  However, it is our belief
- *           right now that this chiplet id will be ICE, which is also zero.
- */
-#define SH1_TIO_PHYS_TO_DMA(x)                                                 \
-       ((((u64)(NASID_GET(x))) << 40) | NODE_OFFSET(x))
-
-#define SH2_NETWORK_BANK_OFFSET(x)                                     \
-        ((u64)(x) & ((1UL << (sn_hub_info->nasid_shift - 4)) -1))
-
-#define SH2_NETWORK_BANK_SELECT(x)                                     \
-        ((((u64)(x) & (0x3UL << (sn_hub_info->nasid_shift - 4)))       \
-               >> (sn_hub_info->nasid_shift - 4)) << 36)
-
-#define SH2_NETWORK_ADDRESS(x)                                                 \
-       (SH2_NETWORK_BANK_OFFSET(x) | SH2_NETWORK_BANK_SELECT(x))
-
-#define SH2_TIO_PHYS_TO_DMA(x)                                                 \
-        (((u64)(NASID_GET(x)) << 40) |         SH2_NETWORK_ADDRESS(x))
-
-#define PHYS_TO_TIODMA(x)                                              \
-       (is_shub1() ? SH1_TIO_PHYS_TO_DMA(x) : SH2_TIO_PHYS_TO_DMA(x))
-
-#define PHYS_TO_DMA(x)                                                 \
-       ((((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x))
-
-
-/*
- * Macros to test for address type.
- */
-#define IS_AMO_ADDRESS(x)      (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_BASE)
-#define IS_AMO_PHYS_ADDRESS(x) (((u64)(x) & (RGN_BITS | AS_MASK)) == AMO_PHYS_BASE)
-
-
-/*
- * The following definitions pertain to the IO special address
- * space.  They define the location of the big and little windows
- * of any given node.
- */
-#define BWIN_SIZE_BITS                 29      /* big window size: 512M */
-#define TIO_BWIN_SIZE_BITS             30      /* big window size: 1G */
-#define NODE_SWIN_BASE(n, w)           ((w == 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \
-               : RAW_NODE_SWIN_BASE(n, w))
-#define TIO_SWIN_BASE(n, w)            (TIO_IO_BASE(n) + \
-                                           ((u64) (w) << TIO_SWIN_SIZE_BITS))
-#define NODE_IO_BASE(n)                        (GLOBAL_MMR_SPACE | NASID_SPACE(n))
-#define TIO_IO_BASE(n)                  (__IA64_UNCACHED_OFFSET | NASID_SPACE(n))
-#define BWIN_SIZE                      (1UL << BWIN_SIZE_BITS)
-#define NODE_BWIN_BASE0(n)             (NODE_IO_BASE(n) + BWIN_SIZE)
-#define NODE_BWIN_BASE(n, w)           (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS))
-#define RAW_NODE_SWIN_BASE(n, w)       (NODE_IO_BASE(n) + ((u64) (w) << SWIN_SIZE_BITS))
-#define BWIN_WIDGET_MASK               0x7
-#define BWIN_WINDOWNUM(x)              (((x) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK)
-#define SH1_IS_BIG_WINDOW_ADDR(x)      ((x) & BWIN_TOP)
-
-#define TIO_BWIN_WINDOW_SELECT_MASK    0x7
-#define TIO_BWIN_WINDOWNUM(x)          (((x) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK)
-
-#define TIO_HWIN_SHIFT_BITS            33
-#define TIO_HWIN(x)                    (NODE_OFFSET(x) >> TIO_HWIN_SHIFT_BITS)
-
-/*
- * The following definitions pertain to the IO special address
- * space.  They define the location of the big and little windows
- * of any given node.
- */
-
-#define SWIN_SIZE_BITS                 24
-#define        SWIN_WIDGET_MASK                0xF
-
-#define TIO_SWIN_SIZE_BITS             28
-#define TIO_SWIN_SIZE                  (1UL << TIO_SWIN_SIZE_BITS)
-#define TIO_SWIN_WIDGET_MASK           0x3
-
-/*
- * Convert smallwindow address to xtalk address.
- *
- * 'addr' can be physical or virtual address, but will be converted
- * to Xtalk address in the range 0 -> SWINZ_SIZEMASK
- */
-#define        SWIN_WIDGETNUM(x)               (((x)  >> SWIN_SIZE_BITS) & SWIN_WIDGET_MASK)
-#define TIO_SWIN_WIDGETNUM(x)          (((x)  >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK)
-
-
-/*
- * The following macros produce the correct base virtual address for
- * the hub registers. The REMOTE_HUB_* macro produce
- * the address for the specified hub's registers.  The intent is
- * that the appropriate PI, MD, NI, or II register would be substituted
- * for x.
- *
- *   WARNING:
- *     When certain Hub chip workaround are defined, it's not sufficient
- *     to dereference the *_HUB_ADDR() macros.  You should instead use
- *     HUB_L() and HUB_S() if you must deal with pointers to hub registers.
- *     Otherwise, the recommended approach is to use *_HUB_L() and *_HUB_S().
- *     They're always safe.
- */
-/* Shub1 TIO & MMR addressing macros */
-#define SH1_TIO_IOSPACE_ADDR(n,x)                                      \
-       GLOBAL_MMR_ADDR(n,x)
-
-#define SH1_REMOTE_BWIN_MMR(n,x)                                       \
-       GLOBAL_MMR_ADDR(n,x)
-
-#define SH1_REMOTE_SWIN_MMR(n,x)                                       \
-       (NODE_SWIN_BASE(n,1) + 0x800000UL + (x))
-
-#define SH1_REMOTE_MMR(n,x)                                            \
-       (SH1_IS_BIG_WINDOW_ADDR(x) ? SH1_REMOTE_BWIN_MMR(n,x) :         \
-               SH1_REMOTE_SWIN_MMR(n,x))
-
-/* Shub1 TIO & MMR addressing macros */
-#define SH2_TIO_IOSPACE_ADDR(n,x)                                      \
-       ((__IA64_UNCACHED_OFFSET | REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2)))
-
-#define SH2_REMOTE_MMR(n,x)                                            \
-       GLOBAL_MMR_ADDR(n,x)
-
-
-/* TIO & MMR addressing macros that work on both shub1 & shub2 */
-#define TIO_IOSPACE_ADDR(n,x)                                          \
-       ((u64 *)(is_shub1() ? SH1_TIO_IOSPACE_ADDR(n,x) :               \
-                SH2_TIO_IOSPACE_ADDR(n,x)))
-
-#define SH_REMOTE_MMR(n,x)                                             \
-       (is_shub1() ? SH1_REMOTE_MMR(n,x) : SH2_REMOTE_MMR(n,x))
-
-#define REMOTE_HUB_ADDR(n,x)                                           \
-       (IS_TIO_NASID(n) ?  ((volatile u64*)TIO_IOSPACE_ADDR(n,x)) :    \
-        ((volatile u64*)SH_REMOTE_MMR(n,x)))
-
-
-#define HUB_L(x)                       (*((volatile typeof(*x) *)x))
-#define        HUB_S(x,d)                      (*((volatile typeof(*x) *)x) = (d))
-
-#define REMOTE_HUB_L(n, a)             HUB_L(REMOTE_HUB_ADDR((n), (a)))
-#define REMOTE_HUB_S(n, a, d)          HUB_S(REMOTE_HUB_ADDR((n), (a)), (d))
-
-/*
- * Coretalk address breakdown
- */
-#define CTALK_NASID_SHFT               40
-#define CTALK_NASID_MASK               (0x3FFFULL << CTALK_NASID_SHFT)
-#define CTALK_CID_SHFT                 38
-#define CTALK_CID_MASK                 (0x3ULL << CTALK_CID_SHFT)
-#define CTALK_NODE_OFFSET              0x3FFFFFFFFF
-
-#endif /* _ASM_IA64_SN_ADDRS_H */
diff --git a/arch/ia64/include/asm/sn/arch.h b/arch/ia64/include/asm/sn/arch.h
deleted file mode 100644 (file)
index 31eb784..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * SGI specific setup.
- *
- * Copyright (C) 1995-1997,1999,2001-2005 Silicon Graphics, Inc.  All rights reserved.
- * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
- */
-#ifndef _ASM_IA64_SN_ARCH_H
-#define _ASM_IA64_SN_ARCH_H
-
-#include <linux/numa.h>
-#include <asm/types.h>
-#include <asm/percpu.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sn_cpuid.h>
-
-/*
- * This is the maximum number of NUMALINK nodes that can be part of a single
- * SSI kernel. This number includes C-brick, M-bricks, and TIOs. Nodes in
- * remote partitions are NOT included in this number.
- * The number of compact nodes cannot exceed size of a coherency domain.
- * The purpose of this define is to specify a node count that includes
- * all C/M/TIO nodes in an SSI system.
- *
- * SGI system can currently support up to 256 C/M nodes plus additional TIO nodes.
- *
- *     Note: ACPI20 has an architectural limit of 256 nodes. When we upgrade
- *     to ACPI3.0, this limit will be removed. The notion of "compact nodes"
- *     should be deleted and TIOs should be included in MAX_NUMNODES.
- */
-#define MAX_TIO_NODES          MAX_NUMNODES
-#define MAX_COMPACT_NODES      (MAX_NUMNODES + MAX_TIO_NODES)
-
-/*
- * Maximum number of nodes in all partitions and in all coherency domains.
- * This is the total number of nodes accessible in the numalink fabric. It
- * includes all C & M bricks, plus all TIOs.
- *
- * This value is also the value of the maximum number of NASIDs in the numalink
- * fabric.
- */
-#define MAX_NUMALINK_NODES     16384
-
-/*
- * The following defines attributes of the HUB chip. These attributes are
- * frequently referenced. They are kept in the per-cpu data areas of each cpu.
- * They are kept together in a struct to minimize cache misses.
- */
-struct sn_hub_info_s {
-       u8 shub2;
-       u8 nasid_shift;
-       u8 as_shift;
-       u8 shub_1_1_found;
-       u16 nasid_bitmask;
-};
-DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
-#define sn_hub_info    this_cpu_ptr(&__sn_hub_info)
-#define is_shub2()     (sn_hub_info->shub2)
-#define is_shub1()     (sn_hub_info->shub2 == 0)
-
-/*
- * Use this macro to test if shub 1.1 wars should be enabled
- */
-#define enable_shub_wars_1_1() (sn_hub_info->shub_1_1_found)
-
-
-/*
- * Compact node ID to nasid mappings kept in the per-cpu data areas of each
- * cpu.
- */
-DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
-#define sn_cnodeid_to_nasid    this_cpu_ptr(&__sn_cnodeid_to_nasid[0])
-
-
-extern u8 sn_partition_id;
-extern u8 sn_system_size;
-extern u8 sn_sharing_domain_size;
-extern u8 sn_region_size;
-
-extern void sn_flush_all_caches(long addr, long bytes);
-extern bool sn_cpu_disable_allowed(int cpu);
-
-#endif /* _ASM_IA64_SN_ARCH_H */
diff --git a/arch/ia64/include/asm/sn/bte.h b/arch/ia64/include/asm/sn/bte.h
deleted file mode 100644 (file)
index cd71ab5..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000-2007 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-
-#ifndef _ASM_IA64_SN_BTE_H
-#define _ASM_IA64_SN_BTE_H
-
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/types.h>
-#include <asm/sn/shub_mmr.h>
-
-struct nodepda_s;
-
-#define IBCT_NOTIFY             (0x1UL << 4)
-#define IBCT_ZFIL_MODE          (0x1UL << 0)
-
-/* #define BTE_DEBUG */
-/* #define BTE_DEBUG_VERBOSE */
-
-#ifdef BTE_DEBUG
-#  define BTE_PRINTK(x) printk x       /* Terse */
-#  ifdef BTE_DEBUG_VERBOSE
-#    define BTE_PRINTKV(x) printk x    /* Verbose */
-#  else
-#    define BTE_PRINTKV(x)
-#  endif /* BTE_DEBUG_VERBOSE */
-#else
-#  define BTE_PRINTK(x)
-#  define BTE_PRINTKV(x)
-#endif /* BTE_DEBUG */
-
-
-/* BTE status register only supports 16 bits for length field */
-#define BTE_LEN_BITS (16)
-#define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1)
-#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT)
-
-
-/* Define hardware */
-#define BTES_PER_NODE (is_shub2() ? 4 : 2)
-#define MAX_BTES_PER_NODE 4
-
-#define BTE2OFF_CTRL   0
-#define BTE2OFF_SRC    (SH2_BT_ENG_SRC_ADDR_0 - SH2_BT_ENG_CSR_0)
-#define BTE2OFF_DEST   (SH2_BT_ENG_DEST_ADDR_0 - SH2_BT_ENG_CSR_0)
-#define BTE2OFF_NOTIFY (SH2_BT_ENG_NOTIF_ADDR_0 - SH2_BT_ENG_CSR_0)
-
-#define BTE_BASE_ADDR(interface)                               \
-    (is_shub2() ? (interface == 0) ? SH2_BT_ENG_CSR_0 :                \
-                 (interface == 1) ? SH2_BT_ENG_CSR_1 :         \
-                 (interface == 2) ? SH2_BT_ENG_CSR_2 :         \
-                                    SH2_BT_ENG_CSR_3           \
-               : (interface == 0) ? IIO_IBLS0 : IIO_IBLS1)
-
-#define BTE_SOURCE_ADDR(base)                                  \
-    (is_shub2() ? base + (BTE2OFF_SRC/8)                       \
-               : base + (BTEOFF_SRC/8))
-
-#define BTE_DEST_ADDR(base)                                    \
-    (is_shub2() ? base + (BTE2OFF_DEST/8)                      \
-               : base + (BTEOFF_DEST/8))
-
-#define BTE_CTRL_ADDR(base)                                    \
-    (is_shub2() ? base + (BTE2OFF_CTRL/8)                      \
-               : base + (BTEOFF_CTRL/8))
-
-#define BTE_NOTIF_ADDR(base)                                   \
-    (is_shub2() ? base + (BTE2OFF_NOTIFY/8)                    \
-               : base + (BTEOFF_NOTIFY/8))
-
-/* Define hardware modes */
-#define BTE_NOTIFY IBCT_NOTIFY
-#define BTE_NORMAL BTE_NOTIFY
-#define BTE_ZERO_FILL (BTE_NOTIFY | IBCT_ZFIL_MODE)
-/* Use a reserved bit to let the caller specify a wait for any BTE */
-#define BTE_WACQUIRE 0x4000
-/* Use the BTE on the node with the destination memory */
-#define BTE_USE_DEST (BTE_WACQUIRE << 1)
-/* Use any available BTE interface on any node for the transfer */
-#define BTE_USE_ANY (BTE_USE_DEST << 1)
-/* macro to force the IBCT0 value valid */
-#define BTE_VALID_MODE(x) ((x) & (IBCT_NOTIFY | IBCT_ZFIL_MODE))
-
-#define BTE_ACTIVE             (IBLS_BUSY | IBLS_ERROR)
-#define BTE_WORD_AVAILABLE     (IBLS_BUSY << 1)
-#define BTE_WORD_BUSY          (~BTE_WORD_AVAILABLE)
-
-/*
- * Some macros to simplify reading.
- * Start with macros to locate the BTE control registers.
- */
-#define BTE_LNSTAT_LOAD(_bte)                                          \
-                       HUB_L(_bte->bte_base_addr)
-#define BTE_LNSTAT_STORE(_bte, _x)                                     \
-                       HUB_S(_bte->bte_base_addr, (_x))
-#define BTE_SRC_STORE(_bte, _x)                                                \
-({                                                                     \
-               u64 __addr = ((_x) & ~AS_MASK);                         \
-               if (is_shub2())                                         \
-                       __addr = SH2_TIO_PHYS_TO_DMA(__addr);           \
-               HUB_S(_bte->bte_source_addr, __addr);                   \
-})
-#define BTE_DEST_STORE(_bte, _x)                                       \
-({                                                                     \
-               u64 __addr = ((_x) & ~AS_MASK);                         \
-               if (is_shub2())                                         \
-                       __addr = SH2_TIO_PHYS_TO_DMA(__addr);           \
-               HUB_S(_bte->bte_destination_addr, __addr);              \
-})
-#define BTE_CTRL_STORE(_bte, _x)                                       \
-                       HUB_S(_bte->bte_control_addr, (_x))
-#define BTE_NOTIF_STORE(_bte, _x)                                      \
-({                                                                     \
-               u64 __addr = ia64_tpa((_x) & ~AS_MASK);                 \
-               if (is_shub2())                                         \
-                       __addr = SH2_TIO_PHYS_TO_DMA(__addr);           \
-               HUB_S(_bte->bte_notify_addr, __addr);                   \
-})
-
-#define BTE_START_TRANSFER(_bte, _len, _mode)                          \
-       is_shub2() ? BTE_CTRL_STORE(_bte, IBLS_BUSY | (_mode << 24) | _len) \
-               : BTE_LNSTAT_STORE(_bte, _len);                         \
-                 BTE_CTRL_STORE(_bte, _mode)
-
-/* Possible results from bte_copy and bte_unaligned_copy */
-/* The following error codes map into the BTE hardware codes
- * IIO_ICRB_ECODE_* (in shubio.h). The hardware uses
- * an error code of 0 (IIO_ICRB_ECODE_DERR), but we want zero
- * to mean BTE_SUCCESS, so add one (BTEFAIL_OFFSET) to the error
- * codes to give the following error codes.
- */
-#define BTEFAIL_OFFSET 1
-
-typedef enum {
-       BTE_SUCCESS,            /* 0 is success */
-       BTEFAIL_DIR,            /* Directory error due to IIO access*/
-       BTEFAIL_POISON,         /* poison error on IO access (write to poison page) */
-       BTEFAIL_WERR,           /* Write error (ie WINV to a Read only line) */
-       BTEFAIL_ACCESS,         /* access error (protection violation) */
-       BTEFAIL_PWERR,          /* Partial Write Error */
-       BTEFAIL_PRERR,          /* Partial Read Error */
-       BTEFAIL_TOUT,           /* CRB Time out */
-       BTEFAIL_XTERR,          /* Incoming xtalk pkt had error bit */
-       BTEFAIL_NOTAVAIL,       /* BTE not available */
-} bte_result_t;
-
-#define BTEFAIL_SH2_RESP_SHORT 0x1     /* bit 000001 */
-#define BTEFAIL_SH2_RESP_LONG  0x2     /* bit 000010 */
-#define BTEFAIL_SH2_RESP_DSP   0x4     /* bit 000100 */
-#define BTEFAIL_SH2_RESP_ACCESS        0x8     /* bit 001000 */
-#define BTEFAIL_SH2_CRB_TO     0x10    /* bit 010000 */
-#define BTEFAIL_SH2_NACK_LIMIT 0x20    /* bit 100000 */
-#define BTEFAIL_SH2_ALL                0x3F    /* bit 111111 */
-
-#define        BTE_ERR_BITS    0x3FUL
-#define        BTE_ERR_SHIFT   36
-#define BTE_ERR_MASK   (BTE_ERR_BITS << BTE_ERR_SHIFT)
-
-#define BTE_ERROR_RETRY(value)                                         \
-       (is_shub2() ? (value != BTEFAIL_SH2_CRB_TO)                     \
-               : (value != BTEFAIL_TOUT))
-
-/*
- * On shub1 BTE_ERR_MASK will always be false, so no need for is_shub2()
- */
-#define BTE_SHUB2_ERROR(_status)                                       \
-       ((_status & BTE_ERR_MASK)                                       \
-          ? (((_status >> BTE_ERR_SHIFT) & BTE_ERR_BITS) | IBLS_ERROR) \
-          : _status)
-
-#define BTE_GET_ERROR_STATUS(_status)                                  \
-       (BTE_SHUB2_ERROR(_status) & ~IBLS_ERROR)
-
-#define BTE_VALID_SH2_ERROR(value)                                     \
-       ((value >= BTEFAIL_SH2_RESP_SHORT) && (value <= BTEFAIL_SH2_ALL))
-
-/*
- * Structure defining a bte.  An instance of this
- * structure is created in the nodepda for each
- * bte on that node (as defined by BTES_PER_NODE)
- * This structure contains everything necessary
- * to work with a BTE.
- */
-struct bteinfo_s {
-       volatile u64 notify ____cacheline_aligned;
-       u64 *bte_base_addr ____cacheline_aligned;
-       u64 *bte_source_addr;
-       u64 *bte_destination_addr;
-       u64 *bte_control_addr;
-       u64 *bte_notify_addr;
-       spinlock_t spinlock;
-       cnodeid_t bte_cnode;    /* cnode                            */
-       int bte_error_count;    /* Number of errors encountered     */
-       int bte_num;            /* 0 --> BTE0, 1 --> BTE1           */
-       int cleanup_active;     /* Interface is locked for cleanup  */
-       volatile bte_result_t bh_error; /* error while processing   */
-       volatile u64 *most_rcnt_na;
-       struct bteinfo_s *btes_to_try[MAX_BTES_PER_NODE];
-};
-
-
-/*
- * Function prototypes (functions defined in bte.c, used elsewhere)
- */
-extern bte_result_t bte_copy(u64, u64, u64, u64, void *);
-extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64);
-extern void bte_error_handler(struct nodepda_s *);
-
-#define bte_zero(dest, len, mode, notification) \
-       bte_copy(0, dest, len, ((mode) | BTE_ZERO_FILL), notification)
-
-/*
- * The following is the preferred way of calling bte_unaligned_copy
- * If the copy is fully cache line aligned, then bte_copy is
- * used instead.  Since bte_copy is inlined, this saves a call
- * stack.  NOTE: bte_copy is called synchronously and does block
- * until the transfer is complete.  In order to get the asynch
- * version of bte_copy, you must perform this check yourself.
- */
-#define BTE_UNALIGNED_COPY(src, dest, len, mode)                       \
-       (((len & (L1_CACHE_BYTES - 1)) ||                               \
-         (src & (L1_CACHE_BYTES - 1)) ||                               \
-         (dest & (L1_CACHE_BYTES - 1))) ?                              \
-        bte_unaligned_copy(src, dest, len, mode) :                     \
-        bte_copy(src, dest, len, mode, NULL))
-
-
-#endif /* _ASM_IA64_SN_BTE_H */
diff --git a/arch/ia64/include/asm/sn/clksupport.h b/arch/ia64/include/asm/sn/clksupport.h
deleted file mode 100644 (file)
index d340c36..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * This file contains definitions for accessing a platform supported high resolution
- * clock. The clock is monitonically increasing and can be accessed from any node
- * in the system. The clock is synchronized across nodes - all nodes see the
- * same value.
- * 
- *     RTC_COUNTER_ADDR - contains the address of the counter 
- *
- */
-
-#ifndef _ASM_IA64_SN_CLKSUPPORT_H
-#define _ASM_IA64_SN_CLKSUPPORT_H
-
-extern unsigned long sn_rtc_cycles_per_second;
-
-#define RTC_COUNTER_ADDR       ((long *)LOCAL_MMR_ADDR(SH_RTC))
-
-#define rtc_time()             (*RTC_COUNTER_ADDR)
-
-#endif /* _ASM_IA64_SN_CLKSUPPORT_H */
diff --git a/arch/ia64/include/asm/sn/geo.h b/arch/ia64/include/asm/sn/geo.h
deleted file mode 100644 (file)
index f083c94..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_GEO_H
-#define _ASM_IA64_SN_GEO_H
-
-/* The geoid_t implementation below is based loosely on the pcfg_t
-   implementation in sys/SN/promcfg.h. */
-
-/* Type declaractions */
-
-/* Size of a geoid_t structure (must be before decl. of geoid_u) */
-#define GEOID_SIZE     8       /* Would 16 be better?  The size can
-                                  be different on different platforms. */
-
-#define MAX_SLOTS      0xf     /* slots per module */
-#define MAX_SLABS      0xf     /* slabs per slot */
-
-typedef unsigned char  geo_type_t;
-
-/* Fields common to all substructures */
-typedef struct geo_common_s {
-    moduleid_t module;         /* The module (box) this h/w lives in */
-    geo_type_t type;           /* What type of h/w is named by this geoid_t */
-    slabid_t   slab:4;         /* slab (ASIC), 0 .. 15 within slot */
-    slotid_t   slot:4;         /* slot (Blade), 0 .. 15 within module */
-} geo_common_t;
-
-/* Additional fields for particular types of hardware */
-typedef struct geo_node_s {
-    geo_common_t       common;         /* No additional fields needed */
-} geo_node_t;
-
-typedef struct geo_rtr_s {
-    geo_common_t       common;         /* No additional fields needed */
-} geo_rtr_t;
-
-typedef struct geo_iocntl_s {
-    geo_common_t       common;         /* No additional fields needed */
-} geo_iocntl_t;
-
-typedef struct geo_pcicard_s {
-    geo_iocntl_t       common;
-    char               bus;    /* Bus/widget number */
-    char               slot;   /* PCI slot number */
-} geo_pcicard_t;
-
-/* Subcomponents of a node */
-typedef struct geo_cpu_s {
-    geo_node_t node;
-    char       slice;          /* Which CPU on the node */
-} geo_cpu_t;
-
-typedef struct geo_mem_s {
-    geo_node_t node;
-    char       membus;         /* The memory bus on the node */
-    char       memslot;        /* The memory slot on the bus */
-} geo_mem_t;
-
-
-typedef union geoid_u {
-    geo_common_t       common;
-    geo_node_t         node;
-    geo_iocntl_t       iocntl;
-    geo_pcicard_t      pcicard;
-    geo_rtr_t          rtr;
-    geo_cpu_t          cpu;
-    geo_mem_t          mem;
-    char               padsize[GEOID_SIZE];
-} geoid_t;
-
-
-/* Preprocessor macros */
-
-#define GEO_MAX_LEN    48      /* max. formatted length, plus some pad:
-                                  module/001c07/slab/5/node/memory/2/slot/4 */
-
-/* Values for geo_type_t */
-#define GEO_TYPE_INVALID       0
-#define GEO_TYPE_MODULE                1
-#define GEO_TYPE_NODE          2
-#define GEO_TYPE_RTR           3
-#define GEO_TYPE_IOCNTL                4
-#define GEO_TYPE_IOCARD                5
-#define GEO_TYPE_CPU           6
-#define GEO_TYPE_MEM           7
-#define GEO_TYPE_MAX           (GEO_TYPE_MEM+1)
-
-/* Parameter for hwcfg_format_geoid_compt() */
-#define GEO_COMPT_MODULE       1
-#define GEO_COMPT_SLAB         2
-#define GEO_COMPT_IOBUS                3
-#define GEO_COMPT_IOSLOT       4
-#define GEO_COMPT_CPU          5
-#define GEO_COMPT_MEMBUS       6
-#define GEO_COMPT_MEMSLOT      7
-
-#define GEO_INVALID_STR                "<invalid>"
-
-#define INVALID_NASID           ((nasid_t)-1)
-#define INVALID_CNODEID         ((cnodeid_t)-1)
-#define INVALID_PNODEID         ((pnodeid_t)-1)
-#define INVALID_SLAB            (slabid_t)-1
-#define INVALID_SLOT            (slotid_t)-1
-#define INVALID_MODULE          ((moduleid_t)-1)
-
-static inline slabid_t geo_slab(geoid_t g)
-{
-       return (g.common.type == GEO_TYPE_INVALID) ?
-               INVALID_SLAB : g.common.slab;
-}
-
-static inline slotid_t geo_slot(geoid_t g)
-{
-       return (g.common.type == GEO_TYPE_INVALID) ?
-               INVALID_SLOT : g.common.slot;
-}
-
-static inline moduleid_t geo_module(geoid_t g)
-{
-       return (g.common.type == GEO_TYPE_INVALID) ?
-               INVALID_MODULE : g.common.module;
-}
-
-extern geoid_t cnodeid_get_geoid(cnodeid_t cnode);
-
-#endif /* _ASM_IA64_SN_GEO_H */
index e0487aa..3885a77 100644 (file)
@@ -9,60 +9,7 @@
 #ifndef _ASM_IA64_SN_INTR_H
 #define _ASM_IA64_SN_INTR_H
 
-#include <linux/rcupdate.h>
-#include <asm/sn/types.h>
-
-#define SGI_UART_VECTOR                0xe9
-
-/* Reserved IRQs : Note, not to exceed IA64_SN2_FIRST_DEVICE_VECTOR */
 #define SGI_XPC_ACTIVATE       0x30
-#define SGI_II_ERROR           0x31
-#define SGI_XBOW_ERROR         0x32
-#define SGI_PCIASIC_ERROR      0x33
-#define SGI_ACPI_SCI_INT       0x34
-#define SGI_TIOCA_ERROR                0x35
-#define SGI_TIO_ERROR          0x36
-#define SGI_TIOCX_ERROR                0x37
-#define SGI_MMTIMER_VECTOR     0x38
 #define SGI_XPC_NOTIFY         0xe7
 
-#define IA64_SN2_FIRST_DEVICE_VECTOR   0x3c
-#define IA64_SN2_LAST_DEVICE_VECTOR    0xe6
-
-#define SN2_IRQ_RESERVED       0x1
-#define SN2_IRQ_CONNECTED      0x2
-#define SN2_IRQ_SHARED         0x4
-
-// The SN PROM irq struct
-struct sn_irq_info {
-       struct sn_irq_info *irq_next;   /* deprecated DO NOT USE     */
-       short           irq_nasid;      /* Nasid IRQ is assigned to  */
-       int             irq_slice;      /* slice IRQ is assigned to  */
-       int             irq_cpuid;      /* kernel logical cpuid      */
-       int             irq_irq;        /* the IRQ number */
-       int             irq_int_bit;    /* Bridge interrupt pin */
-                                       /* <0 means MSI */
-       u64     irq_xtalkaddr;  /* xtalkaddr IRQ is sent to  */
-       int             irq_bridge_type;/* pciio asic type (pciio.h) */
-       void           *irq_bridge;     /* bridge generating irq     */
-       void           *irq_pciioinfo;  /* associated pciio_info_t   */
-       int             irq_last_intr;  /* For Shub lb lost intr WAR */
-       int             irq_cookie;     /* unique cookie             */
-       int             irq_flags;      /* flags */
-       int             irq_share_cnt;  /* num devices sharing IRQ   */
-       struct list_head        list;   /* list of sn_irq_info structs */
-       struct rcu_head         rcu;    /* rcu callback list */
-};
-
-extern void sn_send_IPI_phys(int, long, int, int);
-extern u64 sn_intr_alloc(nasid_t, int,
-                             struct sn_irq_info *,
-                             int, nasid_t, int);
-extern void sn_intr_free(nasid_t, int, struct sn_irq_info *);
-extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int);
-extern void sn_set_err_irq_affinity(unsigned int);
-extern struct list_head **sn_irq_lh;
-
-#define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector)
-
 #endif /* _ASM_IA64_SN_INTR_H */
diff --git a/arch/ia64/include/asm/sn/io.h b/arch/ia64/include/asm/sn/io.h
deleted file mode 100644 (file)
index 41c73a7..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/* 
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_SN_IO_H
-#define _ASM_SN_IO_H
-#include <linux/compiler.h>
-#include <asm/intrinsics.h>
-
-extern void * sn_io_addr(unsigned long port) __attribute_const__; /* Forward definition */
-extern void __sn_mmiowb(void); /* Forward definition */
-
-extern int num_cnodes;
-
-#define __sn_mf_a()   ia64_mfa()
-
-extern void sn_dma_flush(unsigned long);
-
-#define __sn_inb ___sn_inb
-#define __sn_inw ___sn_inw
-#define __sn_inl ___sn_inl
-#define __sn_outb ___sn_outb
-#define __sn_outw ___sn_outw
-#define __sn_outl ___sn_outl
-#define __sn_readb ___sn_readb
-#define __sn_readw ___sn_readw
-#define __sn_readl ___sn_readl
-#define __sn_readq ___sn_readq
-#define __sn_readb_relaxed ___sn_readb_relaxed
-#define __sn_readw_relaxed ___sn_readw_relaxed
-#define __sn_readl_relaxed ___sn_readl_relaxed
-#define __sn_readq_relaxed ___sn_readq_relaxed
-
-/*
- * Convenience macros for setting/clearing bits using the above accessors
- */
-
-#define __sn_setq_relaxed(addr, val) \
-       writeq((__sn_readq_relaxed(addr) | (val)), (addr))
-#define __sn_clrq_relaxed(addr, val) \
-       writeq((__sn_readq_relaxed(addr) & ~(val)), (addr))
-
-/*
- * The following routines are SN Platform specific, called when
- * a reference is made to inX/outX set macros.  SN Platform
- * inX set of macros ensures that Posted DMA writes on the
- * Bridge is flushed.
- *
- * The routines should be self explainatory.
- */
-
-static inline unsigned int
-___sn_inb (unsigned long port)
-{
-       volatile unsigned char *addr;
-       unsigned char ret = -1;
-
-       if ((addr = sn_io_addr(port))) {
-               ret = *addr;
-               __sn_mf_a();
-               sn_dma_flush((unsigned long)addr);
-       }
-       return ret;
-}
-
-static inline unsigned int
-___sn_inw (unsigned long port)
-{
-       volatile unsigned short *addr;
-       unsigned short ret = -1;
-
-       if ((addr = sn_io_addr(port))) {
-               ret = *addr;
-               __sn_mf_a();
-               sn_dma_flush((unsigned long)addr);
-       }
-       return ret;
-}
-
-static inline unsigned int
-___sn_inl (unsigned long port)
-{
-       volatile unsigned int *addr;
-       unsigned int ret = -1;
-
-       if ((addr = sn_io_addr(port))) {
-               ret = *addr;
-               __sn_mf_a();
-               sn_dma_flush((unsigned long)addr);
-       }
-       return ret;
-}
-
-static inline void
-___sn_outb (unsigned char val, unsigned long port)
-{
-       volatile unsigned char *addr;
-
-       if ((addr = sn_io_addr(port))) {
-               *addr = val;
-               __sn_mmiowb();
-       }
-}
-
-static inline void
-___sn_outw (unsigned short val, unsigned long port)
-{
-       volatile unsigned short *addr;
-
-       if ((addr = sn_io_addr(port))) {
-               *addr = val;
-               __sn_mmiowb();
-       }
-}
-
-static inline void
-___sn_outl (unsigned int val, unsigned long port)
-{
-       volatile unsigned int *addr;
-
-       if ((addr = sn_io_addr(port))) {
-               *addr = val;
-               __sn_mmiowb();
-       }
-}
-
-/*
- * The following routines are SN Platform specific, called when 
- * a reference is made to readX/writeX set macros.  SN Platform 
- * readX set of macros ensures that Posted DMA writes on the 
- * Bridge is flushed.
- * 
- * The routines should be self explainatory.
- */
-
-static inline unsigned char
-___sn_readb (const volatile void __iomem *addr)
-{
-       unsigned char val;
-
-       val = *(volatile unsigned char __force *)addr;
-       __sn_mf_a();
-       sn_dma_flush((unsigned long)addr);
-        return val;
-}
-
-static inline unsigned short
-___sn_readw (const volatile void __iomem *addr)
-{
-       unsigned short val;
-
-       val = *(volatile unsigned short __force *)addr;
-       __sn_mf_a();
-       sn_dma_flush((unsigned long)addr);
-        return val;
-}
-
-static inline unsigned int
-___sn_readl (const volatile void __iomem *addr)
-{
-       unsigned int val;
-
-       val = *(volatile unsigned int __force *)addr;
-       __sn_mf_a();
-       sn_dma_flush((unsigned long)addr);
-        return val;
-}
-
-static inline unsigned long
-___sn_readq (const volatile void __iomem *addr)
-{
-       unsigned long val;
-
-       val = *(volatile unsigned long __force *)addr;
-       __sn_mf_a();
-       sn_dma_flush((unsigned long)addr);
-        return val;
-}
-
-/*
- * For generic and SN2 kernels, we have a set of fast access
- * PIO macros. These macros are provided on SN Platform
- * because the normal inX and readX macros perform an
- * additional task of flushing Post DMA request on the Bridge.
- *
- * These routines should be self explainatory.
- */
-
-static inline unsigned int
-sn_inb_fast (unsigned long port)
-{
-       volatile unsigned char *addr = (unsigned char *)port;
-       unsigned char ret;
-
-       ret = *addr;
-       __sn_mf_a();
-       return ret;
-}
-
-static inline unsigned int
-sn_inw_fast (unsigned long port)
-{
-       volatile unsigned short *addr = (unsigned short *)port;
-       unsigned short ret;
-
-       ret = *addr;
-       __sn_mf_a();
-       return ret;
-}
-
-static inline unsigned int
-sn_inl_fast (unsigned long port)
-{
-       volatile unsigned int *addr = (unsigned int *)port;
-       unsigned int ret;
-
-       ret = *addr;
-       __sn_mf_a();
-       return ret;
-}
-
-static inline unsigned char
-___sn_readb_relaxed (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned char __force *)addr;
-}
-
-static inline unsigned short
-___sn_readw_relaxed (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned short __force *)addr;
-}
-
-static inline unsigned int
-___sn_readl_relaxed (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned int __force *) addr;
-}
-
-static inline unsigned long
-___sn_readq_relaxed (const volatile void __iomem *addr)
-{
-       return *(volatile unsigned long __force *) addr;
-}
-
-struct pci_dev;
-
-static inline int
-sn_pci_set_vchan(struct pci_dev *pci_dev, unsigned long *addr, int vchan)
-{
-
-       if (vchan > 1) {
-               return -1;
-       }
-
-       if (!(*addr >> 32))     /* Using a mask here would be cleaner */
-               return 0;       /* but this generates better code */
-
-       if (vchan == 1) {
-               /* Set Bit 57 */
-               *addr |= (1UL << 57);
-       } else {
-               /* Clear Bit 57 */
-               *addr &= ~(1UL << 57);
-       }
-
-       return 0;
-}
-
-#endif /* _ASM_SN_IO_H */
diff --git a/arch/ia64/include/asm/sn/ioc3.h b/arch/ia64/include/asm/sn/ioc3.h
deleted file mode 100644 (file)
index d4a5249..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2005 Silicon Graphics, Inc.
- */
-#ifndef IA64_SN_IOC3_H
-#define IA64_SN_IOC3_H
-
-/* serial port register map */
-struct ioc3_serialregs {
-       uint32_t sscr;
-       uint32_t stpir;
-       uint32_t stcir;
-       uint32_t srpir;
-       uint32_t srcir;
-       uint32_t srtr;
-       uint32_t shadow;
-};
-
-/* SUPERIO uart register map */
-struct ioc3_uartregs {
-       char iu_lcr;
-       union {
-               char iir;       /* read only */
-               char fcr;       /* write only */
-       } u3;
-       union {
-               char ier;       /* DLAB == 0 */
-               char dlm;       /* DLAB == 1 */
-       } u2;
-       union {
-               char rbr;       /* read only, DLAB == 0 */
-               char thr;       /* write only, DLAB == 0 */
-               char dll;       /* DLAB == 1 */
-       } u1;
-       char iu_scr;
-       char iu_msr;
-       char iu_lsr;
-       char iu_mcr;
-};
-
-#define iu_rbr u1.rbr
-#define iu_thr u1.thr
-#define iu_dll u1.dll
-#define iu_ier u2.ier
-#define iu_dlm u2.dlm
-#define iu_iir u3.iir
-#define iu_fcr u3.fcr
-
-struct ioc3_sioregs {
-       char fill[0x170];
-       struct ioc3_uartregs uartb;
-       struct ioc3_uartregs uarta;
-};
-
-/* PCI IO/mem space register map */
-struct ioc3 {
-       uint32_t pci_id;
-       uint32_t pci_scr;
-       uint32_t pci_rev;
-       uint32_t pci_lat;
-       uint32_t pci_addr;
-       uint32_t pci_err_addr_l;
-       uint32_t pci_err_addr_h;
-
-       uint32_t sio_ir;
-       /* these registers are read-only for general kernel code. To
-        * modify them use the functions in ioc3.c
-        */
-       uint32_t sio_ies;
-       uint32_t sio_iec;
-       uint32_t sio_cr;
-       uint32_t int_out;
-       uint32_t mcr;
-       uint32_t gpcr_s;
-       uint32_t gpcr_c;
-       uint32_t gpdr;
-       uint32_t gppr[9];
-       char fill[0x4c];
-
-       /* serial port registers */
-       uint32_t sbbr_h;
-       uint32_t sbbr_l;
-
-       struct ioc3_serialregs port_a;
-       struct ioc3_serialregs port_b;
-       char fill1[0x1ff10];
-       /* superio registers */
-       struct ioc3_sioregs sregs;
-};
-
-/* These don't exist on the ioc3 serial card... */
-#define eier   fill1[8]
-#define eisr   fill1[4]
-
-#define PCI_LAT                        0xc     /* Latency Timer */
-#define PCI_SCR_DROP_MODE_EN   0x00008000 /* drop pios on parity err */
-#define UARTA_BASE             0x178
-#define UARTB_BASE             0x170
-
-
-/* bitmasks for serial RX status byte */
-#define RXSB_OVERRUN           0x01    /* char(s) lost */
-#define RXSB_PAR_ERR           0x02    /* parity error */
-#define RXSB_FRAME_ERR         0x04    /* framing error */
-#define RXSB_BREAK             0x08    /* break character */
-#define RXSB_CTS               0x10    /* state of CTS */
-#define RXSB_DCD               0x20    /* state of DCD */
-#define RXSB_MODEM_VALID       0x40    /* DCD, CTS and OVERRUN are valid */
-#define RXSB_DATA_VALID                0x80    /* FRAME_ERR PAR_ERR & BREAK valid */
-
-/* bitmasks for serial TX control byte */
-#define TXCB_INT_WHEN_DONE     0x20    /* interrupt after this byte is sent */
-#define TXCB_INVALID           0x00    /* byte is invalid */
-#define TXCB_VALID             0x40    /* byte is valid */
-#define TXCB_MCR               0x80    /* data<7:0> to modem cntrl register */
-#define TXCB_DELAY             0xc0    /* delay data<7:0> mSec */
-
-/* bitmasks for SBBR_L */
-#define SBBR_L_SIZE            0x00000001      /* 0 1KB rings, 1 4KB rings */
-
-/* bitmasks for SSCR_<A:B> */
-#define SSCR_RX_THRESHOLD      0x000001ff      /* hiwater mark */
-#define SSCR_TX_TIMER_BUSY     0x00010000      /* TX timer in progress */
-#define SSCR_HFC_EN            0x00020000      /* h/w flow cntrl enabled */
-#define SSCR_RX_RING_DCD       0x00040000      /* postRX record on delta-DCD */
-#define SSCR_RX_RING_CTS       0x00080000      /* postRX record on delta-CTS */
-#define SSCR_HIGH_SPD          0x00100000      /* 4X speed */
-#define SSCR_DIAG              0x00200000      /* bypass clock divider */
-#define SSCR_RX_DRAIN          0x08000000      /* drain RX buffer to memory */
-#define SSCR_DMA_EN            0x10000000      /* enable ring buffer DMA */
-#define SSCR_DMA_PAUSE         0x20000000      /* pause DMA */
-#define SSCR_PAUSE_STATE       0x40000000      /* set when PAUSE takes effect*/
-#define SSCR_RESET             0x80000000      /* reset DMA channels */
-
-/* all producer/consumer pointers are the same bitfield */
-#define PROD_CONS_PTR_4K       0x00000ff8      /* for 4K buffers */
-#define PROD_CONS_PTR_1K       0x000003f8      /* for 1K buffers */
-#define PROD_CONS_PTR_OFF      3
-
-/* bitmasks for SRCIR_<A:B> */
-#define SRCIR_ARM              0x80000000      /* arm RX timer */
-
-/* bitmasks for SHADOW_<A:B> */
-#define SHADOW_DR              0x00000001      /* data ready */
-#define SHADOW_OE              0x00000002      /* overrun error */
-#define SHADOW_PE              0x00000004      /* parity error */
-#define SHADOW_FE              0x00000008      /* framing error */
-#define SHADOW_BI              0x00000010      /* break interrupt */
-#define SHADOW_THRE            0x00000020      /* transmit holding reg empty */
-#define SHADOW_TEMT            0x00000040      /* transmit shift reg empty */
-#define SHADOW_RFCE            0x00000080      /* char in RX fifo has error */
-#define SHADOW_DCTS            0x00010000      /* delta clear to send */
-#define SHADOW_DDCD            0x00080000      /* delta data carrier detect */
-#define SHADOW_CTS             0x00100000      /* clear to send */
-#define SHADOW_DCD             0x00800000      /* data carrier detect */
-#define SHADOW_DTR             0x01000000      /* data terminal ready */
-#define SHADOW_RTS             0x02000000      /* request to send */
-#define SHADOW_OUT1            0x04000000      /* 16550 OUT1 bit */
-#define SHADOW_OUT2            0x08000000      /* 16550 OUT2 bit */
-#define SHADOW_LOOP            0x10000000      /* loopback enabled */
-
-/* bitmasks for SRTR_<A:B> */
-#define SRTR_CNT               0x00000fff      /* reload value for RX timer */
-#define SRTR_CNT_VAL           0x0fff0000      /* current value of RX timer */
-#define SRTR_CNT_VAL_SHIFT     16
-#define SRTR_HZ                        16000           /* SRTR clock frequency */
-
-/* bitmasks for SIO_IR, SIO_IEC and SIO_IES  */
-#define SIO_IR_SA_TX_MT                0x00000001      /* Serial port A TX empty */
-#define SIO_IR_SA_RX_FULL      0x00000002      /* port A RX buf full */
-#define SIO_IR_SA_RX_HIGH      0x00000004      /* port A RX hiwat */
-#define SIO_IR_SA_RX_TIMER     0x00000008      /* port A RX timeout */
-#define SIO_IR_SA_DELTA_DCD    0x00000010      /* port A delta DCD */
-#define SIO_IR_SA_DELTA_CTS    0x00000020      /* port A delta CTS */
-#define SIO_IR_SA_INT          0x00000040      /* port A pass-thru intr */
-#define SIO_IR_SA_TX_EXPLICIT  0x00000080      /* port A explicit TX thru */
-#define SIO_IR_SA_MEMERR       0x00000100      /* port A PCI error */
-#define SIO_IR_SB_TX_MT                0x00000200
-#define SIO_IR_SB_RX_FULL      0x00000400
-#define SIO_IR_SB_RX_HIGH      0x00000800
-#define SIO_IR_SB_RX_TIMER     0x00001000
-#define SIO_IR_SB_DELTA_DCD    0x00002000
-#define SIO_IR_SB_DELTA_CTS    0x00004000
-#define SIO_IR_SB_INT          0x00008000
-#define SIO_IR_SB_TX_EXPLICIT  0x00010000
-#define SIO_IR_SB_MEMERR       0x00020000
-#define SIO_IR_PP_INT          0x00040000      /* P port pass-thru intr */
-#define SIO_IR_PP_INTA         0x00080000      /* PP context A thru */
-#define SIO_IR_PP_INTB         0x00100000      /* PP context B thru */
-#define SIO_IR_PP_MEMERR       0x00200000      /* PP PCI error */
-#define SIO_IR_KBD_INT         0x00400000      /* kbd/mouse intr */
-#define SIO_IR_RT_INT          0x08000000      /* RT output pulse */
-#define SIO_IR_GEN_INT1                0x10000000      /* RT input pulse */
-#define SIO_IR_GEN_INT_SHIFT   28
-
-/* per device interrupt masks */
-#define SIO_IR_SA              (SIO_IR_SA_TX_MT | \
-                                SIO_IR_SA_RX_FULL | \
-                                SIO_IR_SA_RX_HIGH | \
-                                SIO_IR_SA_RX_TIMER | \
-                                SIO_IR_SA_DELTA_DCD | \
-                                SIO_IR_SA_DELTA_CTS | \
-                                SIO_IR_SA_INT | \
-                                SIO_IR_SA_TX_EXPLICIT | \
-                                SIO_IR_SA_MEMERR)
-
-#define SIO_IR_SB              (SIO_IR_SB_TX_MT | \
-                                SIO_IR_SB_RX_FULL | \
-                                SIO_IR_SB_RX_HIGH | \
-                                SIO_IR_SB_RX_TIMER | \
-                                SIO_IR_SB_DELTA_DCD | \
-                                SIO_IR_SB_DELTA_CTS | \
-                                SIO_IR_SB_INT | \
-                                SIO_IR_SB_TX_EXPLICIT | \
-                                SIO_IR_SB_MEMERR)
-
-#define SIO_IR_PP              (SIO_IR_PP_INT | SIO_IR_PP_INTA | \
-                                SIO_IR_PP_INTB | SIO_IR_PP_MEMERR)
-#define SIO_IR_RT              (SIO_IR_RT_INT | SIO_IR_GEN_INT1)
-
-/* bitmasks for SIO_CR */
-#define SIO_CR_CMD_PULSE_SHIFT 15
-#define SIO_CR_SER_A_BASE_SHIFT 1
-#define SIO_CR_SER_B_BASE_SHIFT 8
-#define SIO_CR_ARB_DIAG                0x00380000      /* cur !enet PCI requet (ro) */
-#define SIO_CR_ARB_DIAG_TXA    0x00000000
-#define SIO_CR_ARB_DIAG_RXA    0x00080000
-#define SIO_CR_ARB_DIAG_TXB    0x00100000
-#define SIO_CR_ARB_DIAG_RXB    0x00180000
-#define SIO_CR_ARB_DIAG_PP     0x00200000
-#define SIO_CR_ARB_DIAG_IDLE   0x00400000      /* 0 -> active request (ro) */
-
-/* defs for some of the generic I/O pins */
-#define GPCR_PHY_RESET         0x20    /* pin is output to PHY reset */
-#define GPCR_UARTB_MODESEL     0x40    /* pin is output to port B mode sel */
-#define GPCR_UARTA_MODESEL     0x80    /* pin is output to port A mode sel */
-
-#define GPPR_PHY_RESET_PIN     5       /* GIO pin controlling phy reset */
-#define GPPR_UARTB_MODESEL_PIN 6       /* GIO pin cntrling uartb modeselect */
-#define GPPR_UARTA_MODESEL_PIN 7       /* GIO pin cntrling uarta modeselect */
-
-#endif /* IA64_SN_IOC3_H */
diff --git a/arch/ia64/include/asm/sn/klconfig.h b/arch/ia64/include/asm/sn/klconfig.h
deleted file mode 100644 (file)
index bcbf209..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Derived from IRIX <sys/SN/klconfig.h>.
- *
- * Copyright (C) 1992-1997,1999,2001-2004 Silicon Graphics, Inc.  All Rights Reserved.
- * Copyright (C) 1999 by Ralf Baechle
- */
-#ifndef _ASM_IA64_SN_KLCONFIG_H
-#define _ASM_IA64_SN_KLCONFIG_H
-
-/*
- * The KLCONFIG structures store info about the various BOARDs found
- * during Hardware Discovery. In addition, it stores info about the
- * components found on the BOARDs.
- */
-
-typedef s32 klconf_off_t;
-
-
-/* Functions/macros needed to use this structure */
-
-typedef struct kl_config_hdr {
-       char            pad[20];
-       klconf_off_t    ch_board_info;  /* the link list of boards */
-       char            pad0[88];
-} kl_config_hdr_t;
-
-
-#define NODE_OFFSET_TO_LBOARD(nasid,off)        (lboard_t*)(GLOBAL_CAC_ADDR((nasid), (off)))
-
-/*
- * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD
- * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to 
- * the LOCAL/current NODE. REMOTE means it is attached to a different
- * node.(TBD - Need a way to treat ROUTER boards.)
- *
- * There are 2 different structures to represent these boards -
- * lboard - Local board, rboard - remote board. These 2 structures
- * can be arbitrarily mixed in the LINKED LIST of BOARDs. (Refer
- * Figure below). The first byte of the rboard or lboard structure
- * is used to find out its type - no unions are used.
- * If it is a lboard, then the config info of this board will be found
- * on the local node. (LOCAL NODE BASE + offset value gives pointer to 
- * the structure.
- * If it is a rboard, the local structure contains the node number
- * and the offset of the beginning of the LINKED LIST on the remote node.
- * The details of the hardware on a remote node can be built locally,
- * if required, by reading the LINKED LIST on the remote node and 
- * ignoring all the rboards on that node.
- *
- * The local node uses the REMOTE NODE NUMBER + OFFSET to point to the 
- * First board info on the remote node. The remote node list is 
- * traversed as the local list, using the REMOTE BASE ADDRESS and not
- * the local base address and ignoring all rboard values.
- *
- * 
- KLCONFIG
-
- +------------+      +------------+      +------------+      +------------+
- |  lboard    |  +-->|   lboard   |  +-->|   rboard   |  +-->|   lboard   |
- +------------+  |   +------------+  |   +------------+  |   +------------+
- | board info |  |   | board info |  |   |errinfo,bptr|  |   | board info |
- +------------+  |   +------------+  |   +------------+  |   +------------+
- | offset     |--+   |  offset    |--+   |  offset    |--+   |offset=NULL |
- +------------+      +------------+      +------------+      +------------+
-
-
- +------------+
- | board info |
- +------------+       +--------------------------------+
- | compt 1    |------>| type, rev, diaginfo, size ...  |  (CPU)
- +------------+       +--------------------------------+
- | compt 2    |--+
- +------------+  |    +--------------------------------+
- |  ...       |  +--->| type, rev, diaginfo, size ...  |  (MEM_BANK)
- +------------+       +--------------------------------+
- | errinfo    |--+
- +------------+  |    +--------------------------------+
-                 +--->|r/l brd errinfo,compt err flags |
-                      +--------------------------------+
-
- *
- * Each BOARD consists of COMPONENTs and the BOARD structure has 
- * pointers (offsets) to its COMPONENT structure.
- * The COMPONENT structure has version info, size and speed info, revision,
- * error info and the NIC info. This structure can accommodate any
- * BOARD with arbitrary COMPONENT composition.
- *
- * The ERRORINFO part of each BOARD has error information
- * that describes errors about the BOARD itself. It also has flags to
- * indicate the COMPONENT(s) on the board that have errors. The error 
- * information specific to the COMPONENT is present in the respective 
- * COMPONENT structure.
- *
- * The ERRORINFO structure is also treated like a COMPONENT, ie. the 
- * BOARD has pointers(offset) to the ERRORINFO structure. The rboard
- * structure also has a pointer to the ERRORINFO structure. This is 
- * the place to store ERRORINFO about a REMOTE NODE, if the HUB on
- * that NODE is not working or if the REMOTE MEMORY is BAD. In cases where 
- * only the CPU of the REMOTE NODE is disabled, the ERRORINFO pointer can
- * be a NODE NUMBER, REMOTE OFFSET combination, pointing to error info 
- * which is present on the REMOTE NODE.(TBD)
- * REMOTE ERRINFO can be stored on any of the nearest nodes 
- * or on all the nearest nodes.(TBD)
- * Like BOARD structures, REMOTE ERRINFO structures can be built locally
- * using the rboard errinfo pointer.
- *
- * In order to get useful information from this Data organization, a set of
- * interface routines are provided (TBD). The important thing to remember while
- * manipulating the structures, is that, the NODE number information should
- * be used. If the NODE is non-zero (remote) then each offset should
- * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR. 
- * This includes offsets for BOARDS, COMPONENTS and ERRORINFO.
- * 
- * Note that these structures do not provide much info about connectivity.
- * That info will be part of HWGRAPH, which is an extension of the cfg_t
- * data structure. (ref IP27prom/cfg.h) It has to be extended to include
- * the IO part of the Network(TBD).
- *
- * The data structures below define the above concepts.
- */
-
-
-/*
- * BOARD classes
- */
-
-#define KLCLASS_MASK   0xf0   
-#define KLCLASS_NONE   0x00
-#define KLCLASS_NODE   0x10             /* CPU, Memory and HUB board */
-#define KLCLASS_CPU    KLCLASS_NODE    
-#define KLCLASS_IO     0x20             /* BaseIO, 4 ch SCSI, ethernet, FDDI 
-                                           and the non-graphics widget boards */
-#define KLCLASS_ROUTER 0x30             /* Router board */
-#define KLCLASS_MIDPLANE 0x40            /* We need to treat this as a board
-                                            so that we can record error info */
-#define KLCLASS_IOBRICK        0x70            /* IP35 iobrick */
-#define KLCLASS_MAX    8               /* Bump this if a new CLASS is added */
-
-#define KLCLASS(_x) ((_x) & KLCLASS_MASK)
-
-
-/*
- * board types
- */
-
-#define KLTYPE_MASK    0x0f
-#define KLTYPE(_x)      ((_x) & KLTYPE_MASK)
-
-#define KLTYPE_SNIA    (KLCLASS_CPU | 0x1)
-#define KLTYPE_TIO     (KLCLASS_CPU | 0x2)
-
-#define KLTYPE_ROUTER     (KLCLASS_ROUTER | 0x1)
-#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3)
-#define KLTYPE_REPEATER_ROUTER (KLCLASS_ROUTER | 0x4)
-
-#define KLTYPE_IOBRICK_XBOW    (KLCLASS_MIDPLANE | 0x2)
-
-#define KLTYPE_IOBRICK         (KLCLASS_IOBRICK | 0x0)
-#define KLTYPE_NBRICK          (KLCLASS_IOBRICK | 0x4)
-#define KLTYPE_PXBRICK         (KLCLASS_IOBRICK | 0x6)
-#define KLTYPE_IXBRICK         (KLCLASS_IOBRICK | 0x7)
-#define KLTYPE_CGBRICK         (KLCLASS_IOBRICK | 0x8)
-#define KLTYPE_OPUSBRICK       (KLCLASS_IOBRICK | 0x9)
-#define KLTYPE_SABRICK          (KLCLASS_IOBRICK | 0xa)
-#define KLTYPE_IABRICK         (KLCLASS_IOBRICK | 0xb)
-#define KLTYPE_PABRICK          (KLCLASS_IOBRICK | 0xc)
-#define KLTYPE_GABRICK         (KLCLASS_IOBRICK | 0xd)
-
-
-/* 
- * board structures
- */
-
-#define MAX_COMPTS_PER_BRD 24
-
-typedef struct lboard_s {
-       klconf_off_t    brd_next_any;     /* Next BOARD */
-       unsigned char   struct_type;      /* type of structure, local or remote */
-       unsigned char   brd_type;         /* type+class */
-       unsigned char   brd_sversion;     /* version of this structure */
-        unsigned char  brd_brevision;    /* board revision */
-        unsigned char  brd_promver;      /* board prom version, if any */
-       unsigned char   brd_flags;        /* Enabled, Disabled etc */
-       unsigned char   brd_slot;         /* slot number */
-       unsigned short  brd_debugsw;      /* Debug switches */
-       geoid_t         brd_geoid;        /* geo id */
-       partid_t        brd_partition;    /* Partition number */
-        unsigned short         brd_diagval;      /* diagnostic value */
-        unsigned short         brd_diagparm;     /* diagnostic parameter */
-        unsigned char  brd_inventory;    /* inventory history */
-        unsigned char  brd_numcompts;    /* Number of components */
-        nic_t          brd_nic;          /* Number in CAN */
-       nasid_t         brd_nasid;        /* passed parameter */
-       klconf_off_t    brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */
-       klconf_off_t    brd_errinfo;      /* Board's error information */
-       struct lboard_s *brd_parent;      /* Logical parent for this brd */
-       char            pad0[4];
-       unsigned char   brd_confidence;   /* confidence that the board is bad */
-       nasid_t         brd_owner;        /* who owns this board */
-       unsigned char   brd_nic_flags;    /* To handle 8 more NICs */
-       char            pad1[24];         /* future expansion */
-       char            brd_name[32];
-       nasid_t         brd_next_same_host; /* host of next brd w/same nasid */
-       klconf_off_t    brd_next_same;    /* Next BOARD with same nasid */
-} lboard_t;
-
-/*
- * Generic info structure. This stores common info about a 
- * component.
- */
-typedef struct klinfo_s {                  /* Generic info */
-        unsigned char   struct_type;       /* type of this structure */
-        unsigned char   struct_version;    /* version of this structure */
-        unsigned char   flags;            /* Enabled, disabled etc */
-        unsigned char   revision;         /* component revision */
-        unsigned short  diagval;          /* result of diagnostics */
-        unsigned short  diagparm;         /* diagnostic parameter */
-        unsigned char   inventory;        /* previous inventory status */
-        unsigned short  partid;                   /* widget part number */
-       nic_t           nic;              /* MUst be aligned properly */
-        unsigned char   physid;           /* physical id of component */
-        unsigned int    virtid;           /* virtual id as seen by system */
-       unsigned char   widid;            /* Widget id - if applicable */
-       nasid_t         nasid;            /* node number - from parent */
-       char            pad1;             /* pad out structure. */
-       char            pad2;             /* pad out structure. */
-       void            *data;
-        klconf_off_t   errinfo;          /* component specific errors */
-        unsigned short  pad3;             /* pci fields have moved over to */
-        unsigned short  pad4;             /* klbri_t */
-} klinfo_t ;
-
-
-static inline lboard_t *find_lboard_next(lboard_t * brd)
-{
-       if (brd && brd->brd_next_any)
-               return NODE_OFFSET_TO_LBOARD(NASID_GET(brd), brd->brd_next_any);
-        return NULL;
-}
-
-#endif /* _ASM_IA64_SN_KLCONFIG_H */
diff --git a/arch/ia64/include/asm/sn/l1.h b/arch/ia64/include/asm/sn/l1.h
deleted file mode 100644 (file)
index 344bf44..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992-1997,2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#ifndef _ASM_IA64_SN_L1_H
-#define _ASM_IA64_SN_L1_H
-
-/* brick type response codes */
-#define L1_BRICKTYPE_PX         0x23            /* # */
-#define L1_BRICKTYPE_PE         0x25            /* % */
-#define L1_BRICKTYPE_N_p0       0x26            /* & */
-#define L1_BRICKTYPE_IP45       0x34            /* 4 */
-#define L1_BRICKTYPE_IP41       0x35            /* 5 */
-#define L1_BRICKTYPE_TWISTER    0x36            /* 6 */ /* IP53 & ROUTER */
-#define L1_BRICKTYPE_IX         0x3d            /* = */
-#define L1_BRICKTYPE_IP34       0x61            /* a */
-#define L1_BRICKTYPE_GA                0x62            /* b */
-#define L1_BRICKTYPE_C          0x63            /* c */
-#define L1_BRICKTYPE_OPUS_TIO  0x66            /* f */
-#define L1_BRICKTYPE_I          0x69            /* i */
-#define L1_BRICKTYPE_N          0x6e            /* n */
-#define L1_BRICKTYPE_OPUS       0x6f           /* o */
-#define L1_BRICKTYPE_P          0x70            /* p */
-#define L1_BRICKTYPE_R          0x72            /* r */
-#define L1_BRICKTYPE_CHI_CG     0x76            /* v */
-#define L1_BRICKTYPE_X          0x78            /* x */
-#define L1_BRICKTYPE_X2         0x79            /* y */
-#define L1_BRICKTYPE_SA                0x5e            /* ^ */
-#define L1_BRICKTYPE_PA                0x6a            /* j */
-#define L1_BRICKTYPE_IA                0x6b            /* k */
-#define L1_BRICKTYPE_ATHENA    0x2b            /* + */
-#define L1_BRICKTYPE_DAYTONA   0x7a            /* z */
-#define L1_BRICKTYPE_1932      0x2c            /* . */
-#define L1_BRICKTYPE_191010    0x2e            /* , */
-
-/* board type response codes */
-#define L1_BOARDTYPE_IP69       0x0100          /* CA */
-#define L1_BOARDTYPE_IP63       0x0200          /* CB */
-#define L1_BOARDTYPE_BASEIO     0x0300          /* IB */
-#define L1_BOARDTYPE_PCIE2SLOT  0x0400          /* IC */
-#define L1_BOARDTYPE_PCIX3SLOT  0x0500          /* ID */
-#define L1_BOARDTYPE_PCIXPCIE4SLOT 0x0600       /* IE */
-#define L1_BOARDTYPE_ABACUS     0x0700          /* AB */
-#define L1_BOARDTYPE_DAYTONA    0x0800          /* AD */
-#define L1_BOARDTYPE_INVAL      (-1)            /* invalid brick type */
-
-#endif /* _ASM_IA64_SN_L1_H */
diff --git a/arch/ia64/include/asm/sn/leds.h b/arch/ia64/include/asm/sn/leds.h
deleted file mode 100644 (file)
index 66cf8c4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_LEDS_H
-#define _ASM_IA64_SN_LEDS_H
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/shub_mmr.h>
-
-#define LED0           (LOCAL_MMR_ADDR(SH_REAL_JUNK_BUS_LED0))
-#define LED_CPU_SHIFT  16
-
-#define LED_CPU_HEARTBEAT      0x01
-#define LED_CPU_ACTIVITY       0x02
-#define LED_ALWAYS_SET         0x00
-
-/*
- * Basic macros for flashing the LEDS on an SGI SN.
- */
-
-static __inline__ void
-set_led_bits(u8 value, u8 mask)
-{
-       pda->led_state = (pda->led_state & ~mask) | (value & mask);
-       *pda->led_address = (short) pda->led_state;
-}
-
-#endif /* _ASM_IA64_SN_LEDS_H */
-
diff --git a/arch/ia64/include/asm/sn/module.h b/arch/ia64/include/asm/sn/module.h
deleted file mode 100644 (file)
index 734e980..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_MODULE_H
-#define _ASM_IA64_SN_MODULE_H
-
-/* parameter for format_module_id() */
-#define MODULE_FORMAT_BRIEF    1
-#define MODULE_FORMAT_LONG     2
-#define MODULE_FORMAT_LCD      3
-
-/*
- *     Module id format
- *
- *     31-16   Rack ID (encoded class, group, number - 16-bit unsigned int)
- *      15-8   Brick type (8-bit ascii character)
- *       7-0   Bay (brick position in rack (0-63) - 8-bit unsigned int)
- *
- */
-
-/*
- * Macros for getting the brick type
- */
-#define MODULE_BTYPE_MASK      0xff00
-#define MODULE_BTYPE_SHFT      8
-#define MODULE_GET_BTYPE(_m)   (((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT)
-#define MODULE_BT_TO_CHAR(_b)  ((char)(_b))
-#define MODULE_GET_BTCHAR(_m)  (MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m)))
-
-/*
- * Macros for getting the rack ID.
- */
-#define MODULE_RACK_MASK       0xffff0000
-#define MODULE_RACK_SHFT       16
-#define MODULE_GET_RACK(_m)    (((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT)
-
-/*
- * Macros for getting the brick position
- */
-#define MODULE_BPOS_MASK       0x00ff
-#define MODULE_BPOS_SHFT       0
-#define MODULE_GET_BPOS(_m)    (((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT)
-
-/*
- * Macros for encoding and decoding rack IDs
- * A rack number consists of three parts:
- *   class (0==CPU/mixed, 1==I/O), group, number
- *
- * Rack number is stored just as it is displayed on the screen:
- * a 3-decimal-digit number.
- */
-#define RACK_CLASS_DVDR         100
-#define RACK_GROUP_DVDR         10
-#define RACK_NUM_DVDR           1
-
-#define RACK_CREATE_RACKID(_c, _g, _n)  ((_c) * RACK_CLASS_DVDR +       \
-        (_g) * RACK_GROUP_DVDR + (_n) * RACK_NUM_DVDR)
-
-#define RACK_GET_CLASS(_r)              ((_r) / RACK_CLASS_DVDR)
-#define RACK_GET_GROUP(_r)              (((_r) - RACK_GET_CLASS(_r) *   \
-            RACK_CLASS_DVDR) / RACK_GROUP_DVDR)
-#define RACK_GET_NUM(_r)                (((_r) - RACK_GET_CLASS(_r) *   \
-            RACK_CLASS_DVDR - RACK_GET_GROUP(_r) *      \
-            RACK_GROUP_DVDR) / RACK_NUM_DVDR)
-
-/*
- * Macros for encoding and decoding rack IDs
- * A rack number consists of three parts:
- *   class      1 bit, 0==CPU/mixed, 1==I/O
- *   group      2 bits for CPU/mixed, 3 bits for I/O
- *   number     3 bits for CPU/mixed, 2 bits for I/O (1 based)
- */
-#define RACK_GROUP_BITS(_r)     (RACK_GET_CLASS(_r) ? 3 : 2)
-#define RACK_NUM_BITS(_r)       (RACK_GET_CLASS(_r) ? 2 : 3)
-
-#define RACK_CLASS_MASK(_r)     0x20
-#define RACK_CLASS_SHFT(_r)     5
-#define RACK_ADD_CLASS(_r, _c)  \
-        ((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r))
-
-#define RACK_GROUP_SHFT(_r)     RACK_NUM_BITS(_r)
-#define RACK_GROUP_MASK(_r)     \
-        ( (((unsigned)1<<RACK_GROUP_BITS(_r)) - 1) << RACK_GROUP_SHFT(_r) )
-#define RACK_ADD_GROUP(_r, _g)  \
-        ((_r) |= (_g) << RACK_GROUP_SHFT(_r) & RACK_GROUP_MASK(_r))
-
-#define RACK_NUM_SHFT(_r)       0
-#define RACK_NUM_MASK(_r)       \
-        ( (((unsigned)1<<RACK_NUM_BITS(_r)) - 1) << RACK_NUM_SHFT(_r) )
-#define RACK_ADD_NUM(_r, _n)    \
-        ((_r) |= ((_n) - 1) << RACK_NUM_SHFT(_r) & RACK_NUM_MASK(_r))
-
-
-/*
- * Brick type definitions
- */
-#define MAX_BRICK_TYPES         256 /* brick type is stored as uchar */
-
-extern char brick_types[];
-
-#define MODULE_CBRICK           0
-#define MODULE_RBRICK           1
-#define MODULE_IBRICK           2
-#define MODULE_KBRICK           3
-#define MODULE_XBRICK           4
-#define MODULE_DBRICK           5
-#define MODULE_PBRICK           6
-#define MODULE_NBRICK           7
-#define MODULE_PEBRICK          8
-#define MODULE_PXBRICK          9
-#define MODULE_IXBRICK          10
-#define MODULE_CGBRICK         11
-#define MODULE_OPUSBRICK        12
-#define MODULE_SABRICK         13      /* TIO BringUp Brick */
-#define MODULE_IABRICK         14
-#define MODULE_PABRICK         15
-#define MODULE_GABRICK         16
-#define MODULE_OPUS_TIO                17      /* OPUS TIO Riser */
-
-extern char brick_types[];
-extern void format_module_id(char *, moduleid_t, int);
-
-#endif /* _ASM_IA64_SN_MODULE_H */
diff --git a/arch/ia64/include/asm/sn/mspec.h b/arch/ia64/include/asm/sn/mspec.h
deleted file mode 100644 (file)
index c1d3c50..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2001-2008 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_MSPEC_H
-#define _ASM_IA64_SN_MSPEC_H
-
-#define FETCHOP_VAR_SIZE 64 /* 64 byte per fetchop variable */
-
-#define FETCHOP_LOAD           0
-#define FETCHOP_INCREMENT      8
-#define FETCHOP_DECREMENT      16
-#define FETCHOP_CLEAR          24
-
-#define FETCHOP_STORE          0
-#define FETCHOP_AND            24
-#define FETCHOP_OR             32
-
-#define FETCHOP_CLEAR_CACHE    56
-
-#define FETCHOP_LOAD_OP(addr, op) ( \
-         *(volatile long *)((char*) (addr) + (op)))
-
-#define FETCHOP_STORE_OP(addr, op, x) ( \
-         *(volatile long *)((char*) (addr) + (op)) = (long) (x))
-
-#ifdef __KERNEL__
-
-/*
- * Each Atomic Memory Operation (amo, formerly known as fetchop)
- * variable is 64 bytes long.  The first 8 bytes are used.  The
- * remaining 56 bytes are unaddressable due to the operation taking
- * that portion of the address.
- *
- * NOTE: The amo structure _MUST_ be placed in either the first or second
- * half of the cache line.  The cache line _MUST NOT_ be used for anything
- * other than additional amo entries.  This is because there are two
- * addresses which reference the same physical cache line.  One will
- * be a cached entry with the memory type bits all set.  This address
- * may be loaded into processor cache.  The amo will be referenced
- * uncached via the memory special memory type.  If any portion of the
- * cached cache-line is modified, when that line is flushed, it will
- * overwrite the uncached value in physical memory and lead to
- * inconsistency.
- */
-struct amo {
-        u64 variable;
-        u64 unused[7];
-};
-
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_IA64_SN_MSPEC_H */
diff --git a/arch/ia64/include/asm/sn/nodepda.h b/arch/ia64/include/asm/sn/nodepda.h
deleted file mode 100644 (file)
index 7c8b471..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_NODEPDA_H
-#define _ASM_IA64_SN_NODEPDA_H
-
-
-#include <asm/irq.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/bte.h>
-
-/*
- * NUMA Node-Specific Data structures are defined in this file.
- * In particular, this is the location of the node PDA.
- * A pointer to the right node PDA is saved in each CPU PDA.
- */
-
-/*
- * Node-specific data structure.
- *
- * One of these structures is allocated on each node of a NUMA system.
- *
- * This structure provides a convenient way of keeping together 
- * all per-node data structures. 
- */
-struct phys_cpuid {
-       short                   nasid;
-       char                    subnode;
-       char                    slice;
-};
-
-struct nodepda_s {
-       void            *pdinfo;        /* Platform-dependent per-node info */
-
-       /*
-        * The BTEs on this node are shared by the local cpus
-        */
-       struct bteinfo_s        bte_if[MAX_BTES_PER_NODE];      /* Virtual Interface */
-       struct timer_list       bte_recovery_timer;
-       spinlock_t              bte_recovery_lock;
-
-       /* 
-        * Array of pointers to the nodepdas for each node.
-        */
-       struct nodepda_s        *pernode_pdaindr[MAX_COMPACT_NODES]; 
-
-       /*
-        * Array of physical cpu identifiers. Indexed by cpuid.
-        */
-       struct phys_cpuid       phys_cpuid[NR_CPUS];
-       spinlock_t              ptc_lock ____cacheline_aligned_in_smp;
-};
-
-typedef struct nodepda_s nodepda_t;
-
-/*
- * Access Functions for node PDA.
- * Since there is one nodepda for each node, we need a convenient mechanism
- * to access these nodepdas without cluttering code with #ifdefs.
- * The next set of definitions provides this.
- * Routines are expected to use 
- *
- *     sn_nodepda   - to access node PDA for the node on which code is running
- *     NODEPDA(cnodeid)   - to access node PDA for cnodeid
- */
-
-DECLARE_PER_CPU(struct nodepda_s *, __sn_nodepda);
-#define sn_nodepda             __this_cpu_read(__sn_nodepda)
-#define        NODEPDA(cnodeid)        (sn_nodepda->pernode_pdaindr[cnodeid])
-
-/*
- * Check if given a compact node id the corresponding node has all the
- * cpus disabled. 
- */
-#define is_headless_node(cnodeid)      (nr_cpus_node(cnodeid) == 0)
-
-#endif /* _ASM_IA64_SN_NODEPDA_H */
diff --git a/arch/ia64/include/asm/sn/pcibr_provider.h b/arch/ia64/include/asm/sn/pcibr_provider.h
deleted file mode 100644 (file)
index da205b7..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992-1997,2000-2006 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
-#define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
-
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibus_provider_defs.h>
-
-/* Workarounds */
-#define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */
-
-#define BUSTYPE_MASK                    0x1
-
-/* Macros given a pcibus structure */
-#define IS_PCIX(ps)     ((ps)->pbi_bridge_mode & BUSTYPE_MASK)
-#define IS_PCI_BRIDGE_ASIC(asic) (asic == PCIIO_ASIC_TYPE_PIC || \
-                asic == PCIIO_ASIC_TYPE_TIOCP)
-#define IS_PIC_SOFT(ps)     (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC)
-#define IS_TIOCP_SOFT(ps)   (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_TIOCP)
-
-
-/*
- * The different PCI Bridge types supported on the SGI Altix platforms
- */
-#define PCIBR_BRIDGETYPE_UNKNOWN       -1
-#define PCIBR_BRIDGETYPE_PIC            2
-#define PCIBR_BRIDGETYPE_TIOCP          3
-
-/*
- * Bridge 64bit Direct Map Attributes
- */
-#define PCI64_ATTR_PREF                 (1ull << 59)
-#define PCI64_ATTR_PREC                 (1ull << 58)
-#define PCI64_ATTR_VIRTUAL              (1ull << 57)
-#define PCI64_ATTR_BAR                  (1ull << 56)
-#define PCI64_ATTR_SWAP                 (1ull << 55)
-#define PCI64_ATTR_VIRTUAL1             (1ull << 54)
-
-#define PCI32_LOCAL_BASE                0
-#define PCI32_MAPPED_BASE               0x40000000
-#define PCI32_DIRECT_BASE               0x80000000
-
-#define IS_PCI32_MAPPED(x)              ((u64)(x) < PCI32_DIRECT_BASE && \
-                                         (u64)(x) >= PCI32_MAPPED_BASE)
-#define IS_PCI32_DIRECT(x)              ((u64)(x) >= PCI32_MAPPED_BASE)
-
-
-/*
- * Bridge PMU Address Transaltion Entry Attibutes
- */
-#define PCI32_ATE_V                     (0x1 << 0)
-#define PCI32_ATE_CO                    (0x1 << 1)     /* PIC ASIC ONLY */
-#define PCI32_ATE_PIO                   (0x1 << 1)     /* TIOCP ASIC ONLY */
-#define PCI32_ATE_MSI                   (0x1 << 2)
-#define PCI32_ATE_PREF                  (0x1 << 3)
-#define PCI32_ATE_BAR                   (0x1 << 4)
-#define PCI32_ATE_ADDR_SHFT             12
-
-#define MINIMAL_ATES_REQUIRED(addr, size) \
-       (IOPG(IOPGOFF(addr) + (size) - 1) == IOPG((size) - 1))
-
-#define MINIMAL_ATE_FLAG(addr, size) \
-       (MINIMAL_ATES_REQUIRED((u64)addr, size) ? 1 : 0)
-
-/* bit 29 of the pci address is the SWAP bit */
-#define ATE_SWAPSHIFT                   29
-#define ATE_SWAP_ON(x)                  ((x) |= (1 << ATE_SWAPSHIFT))
-#define ATE_SWAP_OFF(x)                 ((x) &= ~(1 << ATE_SWAPSHIFT))
-
-/*
- * I/O page size
- */
-#if PAGE_SIZE < 16384
-#define IOPFNSHIFT                      12      /* 4K per mapped page */
-#else
-#define IOPFNSHIFT                      14      /* 16K per mapped page */
-#endif
-
-#define IOPGSIZE                        (1 << IOPFNSHIFT)
-#define IOPG(x)                         ((x) >> IOPFNSHIFT)
-#define IOPGOFF(x)                      ((x) & (IOPGSIZE-1))
-
-#define PCIBR_DEV_SWAP_DIR              (1ull << 19)
-#define PCIBR_CTRL_PAGE_SIZE            (0x1 << 21)
-
-/*
- * PMU resources.
- */
-struct ate_resource{
-       u64 *ate;
-       u64 num_ate;
-       u64 lowest_free_index;
-};
-
-struct pcibus_info {
-       struct pcibus_bussoft   pbi_buscommon;   /* common header */
-       u32                pbi_moduleid;
-       short                   pbi_bridge_type;
-       short                   pbi_bridge_mode;
-
-       struct ate_resource     pbi_int_ate_resource;
-       u64                pbi_int_ate_size;
-
-       u64                pbi_dir_xbase;
-       char                    pbi_hub_xid;
-
-       u64                pbi_devreg[8];
-
-       u32             pbi_valid_devices;
-       u32             pbi_enabled_devices;
-
-       spinlock_t              pbi_lock;
-};
-
-extern int  pcibr_init_provider(void);
-extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *);
-extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type);
-extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type);
-extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
-
-/*
- * prototypes for the bridge asic register access routines in pcibr_reg.c
- */
-extern void             pcireg_control_bit_clr(struct pcibus_info *, u64);
-extern void             pcireg_control_bit_set(struct pcibus_info *, u64);
-extern u64         pcireg_tflush_get(struct pcibus_info *);
-extern u64         pcireg_intr_status_get(struct pcibus_info *);
-extern void             pcireg_intr_enable_bit_clr(struct pcibus_info *, u64);
-extern void             pcireg_intr_enable_bit_set(struct pcibus_info *, u64);
-extern void             pcireg_intr_addr_addr_set(struct pcibus_info *, int, u64);
-extern void             pcireg_force_intr_set(struct pcibus_info *, int);
-extern u64         pcireg_wrb_flush_get(struct pcibus_info *, int);
-extern void             pcireg_int_ate_set(struct pcibus_info *, int, u64);
-extern u64 __iomem *   pcireg_int_ate_addr(struct pcibus_info *, int);
-extern void            pcibr_force_interrupt(struct sn_irq_info *sn_irq_info);
-extern void            pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info);
-extern int             pcibr_ate_alloc(struct pcibus_info *, int);
-extern void            pcibr_ate_free(struct pcibus_info *, int);
-extern void            ate_write(struct pcibus_info *, int, int, u64);
-extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
-                                void *resp, char **ssdt);
-extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
-                                 int action, void *resp);
-extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus);
-#endif
diff --git a/arch/ia64/include/asm/sn/pcibus_provider_defs.h b/arch/ia64/include/asm/sn/pcibus_provider_defs.h
deleted file mode 100644 (file)
index 8f7c83d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
-#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
-
-/*
- * SN pci asic types.  Do not ever renumber these or reuse values.  The
- * values must agree with what prom thinks they are.
- */
-
-#define PCIIO_ASIC_TYPE_UNKNOWN        0
-#define PCIIO_ASIC_TYPE_PPB    1
-#define PCIIO_ASIC_TYPE_PIC    2
-#define PCIIO_ASIC_TYPE_TIOCP  3
-#define PCIIO_ASIC_TYPE_TIOCA  4
-#define PCIIO_ASIC_TYPE_TIOCE  5
-
-#define PCIIO_ASIC_MAX_TYPES   6
-
-/*
- * Common pciio bus provider data.  There should be one of these as the
- * first field in any pciio based provider soft structure (e.g. pcibr_soft
- * tioca_soft, etc).
- */
-
-struct pcibus_bussoft {
-       u32             bs_asic_type;   /* chipset type */
-       u32             bs_xid;         /* xwidget id */
-       u32             bs_persist_busnum; /* Persistent Bus Number */
-       u32             bs_persist_segment; /* Segment Number */
-       u64             bs_legacy_io;   /* legacy io pio addr */
-       u64             bs_legacy_mem;  /* legacy mem pio addr */
-       u64             bs_base;        /* widget base */
-       struct xwidget_info     *bs_xwidget_info;
-};
-
-struct pci_controller;
-/*
- * SN pci bus indirection
- */
-
-struct sn_pcibus_provider {
-       dma_addr_t      (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags);
-       dma_addr_t      (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags);
-       void            (*dma_unmap)(struct pci_dev *, dma_addr_t, int);
-       void *          (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
-       void            (*force_interrupt)(struct sn_irq_info *);
-       void            (*target_interrupt)(struct sn_irq_info *);
-};
-
-/*
- * Flags used by the map interfaces
- * bits 3:0 specifies format of passed in address
- * bit  4   specifies that address is to be used for MSI
- */
-
-#define SN_DMA_ADDRTYPE(x)     ((x) & 0xf)
-#define     SN_DMA_ADDR_PHYS   1       /* address is an xio address. */
-#define     SN_DMA_ADDR_XIO    2       /* address is phys memory */
-#define SN_DMA_MSI             0x10    /* Bus address is to be used for MSI */
-
-extern struct sn_pcibus_provider *sn_pci_provider[];
-#endif                         /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
diff --git a/arch/ia64/include/asm/sn/pcidev.h b/arch/ia64/include/asm/sn/pcidev.h
deleted file mode 100644 (file)
index 1c2382c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2006 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PCIDEV_H
-#define _ASM_IA64_SN_PCI_PCIDEV_H
-
-#include <linux/pci.h>
-
-/*
- * In ia64, pci_dev->sysdata must be a *pci_controller. To provide access to
- * the pcidev_info structs for all devices under a controller, we keep a
- * list of pcidev_info under pci_controller->platform_data.
- */
-struct sn_platform_data {
-       void *provider_soft;
-       struct list_head pcidev_info;
-};
-
-#define SN_PLATFORM_DATA(busdev) \
-       ((struct sn_platform_data *)(PCI_CONTROLLER(busdev)->platform_data))
-
-#define SN_PCIDEV_INFO(dev)    sn_pcidev_info_get(dev)
-
-/*
- * Given a pci_bus, return the sn pcibus_bussoft struct.  Note that
- * this only works for root busses, not for busses represented by PPB's.
- */
-
-#define SN_PCIBUS_BUSSOFT(pci_bus) \
-       ((struct pcibus_bussoft *)(SN_PLATFORM_DATA(pci_bus)->provider_soft))
-
-#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
-       ((struct pcibus_info *)(SN_PLATFORM_DATA(pci_bus)->provider_soft))
-/*
- * Given a struct pci_dev, return the sn pcibus_bussoft struct.  Note
- * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
- * due to possible PPB's in the path.
- */
-
-#define SN_PCIDEV_BUSSOFT(pci_dev) \
-       (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info)
-
-#define SN_PCIDEV_BUSPROVIDER(pci_dev) \
-       (SN_PCIDEV_INFO(pci_dev)->pdi_provider)
-
-#define PCIIO_BUS_NONE 255      /* bus 255 reserved */
-#define PCIIO_SLOT_NONE 255
-#define PCIIO_FUNC_NONE 255
-#define PCIIO_VENDOR_ID_NONE   (-1)
-
-struct pcidev_info {
-       u64             pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */
-       u64             pdi_slot_host_handle;   /* Bus and devfn Host pci_dev */
-
-       struct pcibus_bussoft   *pdi_pcibus_info;       /* Kernel common bus soft */
-       struct pcidev_info      *pdi_host_pcidev_info;  /* Kernel Host pci_dev */
-       struct pci_dev          *pdi_linux_pcidev;      /* Kernel pci_dev */
-
-       struct sn_irq_info      *pdi_sn_irq_info;
-       struct sn_pcibus_provider *pdi_provider;        /* sn pci ops */
-       struct pci_dev          *host_pci_dev;          /* host bus link */
-       struct list_head        pdi_list;               /* List of pcidev_info */
-};
-
-extern void sn_irq_fixup(struct pci_dev *pci_dev,
-                        struct sn_irq_info *sn_irq_info);
-extern void sn_irq_unfixup(struct pci_dev *pci_dev);
-extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
-extern void sn_bus_fixup(struct pci_bus *);
-extern void sn_acpi_bus_fixup(struct pci_bus *);
-extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *);
-extern void sn_bus_store_sysdata(struct pci_dev *dev);
-extern void sn_bus_free_sysdata(void);
-extern void sn_generate_path(struct pci_bus *pci_bus, char *address);
-extern void sn_io_slot_fixup(struct pci_dev *);
-extern void sn_acpi_slot_fixup(struct pci_dev *);
-extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *,
-                             struct sn_irq_info *);
-extern void sn_pci_unfixup_slot(struct pci_dev *dev);
-extern void sn_irq_lh_init(void);
-#endif                         /* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/arch/ia64/include/asm/sn/pda.h b/arch/ia64/include/asm/sn/pda.h
deleted file mode 100644 (file)
index 22ae358..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PDA_H
-#define _ASM_IA64_SN_PDA_H
-
-#include <linux/cache.h>
-#include <asm/percpu.h>
-
-
-/*
- * CPU-specific data structure.
- *
- * One of these structures is allocated for each cpu of a NUMA system.
- *
- * This structure provides a convenient way of keeping together 
- * all SN per-cpu data structures. 
- */
-
-typedef struct pda_s {
-
-       /*
-        * Support for SN LEDs
-        */
-       volatile short  *led_address;
-       u8              led_state;
-       u8              hb_state;       /* supports blinking heartbeat leds */
-       unsigned int    hb_count;
-
-       unsigned int    idle_flag;
-       
-       volatile unsigned long *bedrock_rev_id;
-       volatile unsigned long *pio_write_status_addr;
-       unsigned long pio_write_status_val;
-       volatile unsigned long *pio_shub_war_cam_addr;
-
-       unsigned long   sn_in_service_ivecs[4];
-       int             sn_lb_int_war_ticks;
-       int             sn_last_irq;
-       int             sn_first_irq;
-} pda_t;
-
-
-#define CACHE_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-
-/*
- * PDA
- * Per-cpu private data area for each cpu. The PDA is located immediately after
- * the IA64 cpu_data area. A full page is allocated for the cp_data area for each
- * cpu but only a small amout of the page is actually used. We put the SNIA PDA
- * in the same page as the cpu_data area. Note that there is a check in the setup
- * code to verify that we don't overflow the page.
- *
- * Seems like we should should cache-line align the pda so that any changes in the
- * size of the cpu_data area don't change cache layout. Should we align to 32, 64, 128
- * or 512 boundary. Each has merits. For now, pick 128 but should be revisited later.
- */
-DECLARE_PER_CPU(struct pda_s, pda_percpu);
-
-#define pda            (&__ia64_per_cpu_var(pda_percpu))
-
-#define pdacpu(cpu)    (&per_cpu(pda_percpu, cpu))
-
-#endif /* _ASM_IA64_SN_PDA_H */
diff --git a/arch/ia64/include/asm/sn/pic.h b/arch/ia64/include/asm/sn/pic.h
deleted file mode 100644 (file)
index 5f9da5f..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_PIC_H
-#define _ASM_IA64_SN_PCI_PIC_H
-
-/*
- * PIC AS DEVICE ZERO
- * ------------------
- *
- * PIC handles PCI/X busses.  PCI/X requires that the 'bridge' (i.e. PIC)
- * be designated as 'device 0'.   That is a departure from earlier SGI
- * PCI bridges.  Because of that we use config space 1 to access the
- * config space of the first actual PCI device on the bus.
- * Here's what the PIC manual says:
- *
- *     The current PCI-X bus specification now defines that the parent
- *     hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC
- *     reduced the total number of devices from 8 to 4 and removed the
- *     device registers and windows, now only supporting devices 0,1,2, and
- *     3. PIC did leave all 8 configuration space windows. The reason was
- *     there was nothing to gain by removing them. Here in lies the problem.
- *     The device numbering we do using 0 through 3 is unrelated to the device
- *     numbering which PCI-X requires in configuration space. In the past we
- *     correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc.
- *     PCI-X requires we start a 1, not 0 and currently the PX brick
- *     does associate our:
- *
- *         device 0 with configuration space window 1,
- *         device 1 with configuration space window 2,
- *         device 2 with configuration space window 3,
- *         device 3 with configuration space window 4.
- *
- * The net effect is that all config space access are off-by-one with
- * relation to other per-slot accesses on the PIC.
- * Here is a table that shows some of that:
- *
- *                               Internal Slot#
- *           |
- *           |     0         1        2         3
- * ----------|---------------------------------------
- * config    |  0x21000   0x22000  0x23000   0x24000
- *           |
- * even rrb  |  0[0]      n/a      1[0]      n/a       [] == implied even/odd
- *           |
- * odd rrb   |  n/a       0[1]     n/a       1[1]
- *           |
- * int dev   |  00       01        10        11
- *           |
- * ext slot# |  1        2         3         4
- * ----------|---------------------------------------
- */
-
-#define PIC_ATE_TARGETID_SHFT           8
-#define PIC_HOST_INTR_ADDR              0x0000FFFFFFFFFFFFUL
-#define PIC_PCI64_ATTR_TARG_SHFT        60
-
-
-/*****************************************************************************
- *********************** PIC MMR structure mapping ***************************
- *****************************************************************************/
-
-/* NOTE: PIC WAR. PV#854697.  PIC does not allow writes just to [31:0]
- * of a 64-bit register.  When writing PIC registers, always write the
- * entire 64 bits.
- */
-
-struct pic {
-
-    /* 0x000000-0x00FFFF -- Local Registers */
-
-    /* 0x000000-0x000057 -- Standard Widget Configuration */
-    u64                p_wid_id;                       /* 0x000000 */
-    u64                p_wid_stat;                     /* 0x000008 */
-    u64                p_wid_err_upper;                /* 0x000010 */
-    u64                p_wid_err_lower;                /* 0x000018 */
-    #define p_wid_err p_wid_err_lower
-    u64                p_wid_control;                  /* 0x000020 */
-    u64                p_wid_req_timeout;              /* 0x000028 */
-    u64                p_wid_int_upper;                /* 0x000030 */
-    u64                p_wid_int_lower;                /* 0x000038 */
-    #define p_wid_int p_wid_int_lower
-    u64                p_wid_err_cmdword;              /* 0x000040 */
-    u64                p_wid_llp;                      /* 0x000048 */
-    u64                p_wid_tflush;                   /* 0x000050 */
-
-    /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */
-    u64                p_wid_aux_err;                  /* 0x000058 */
-    u64                p_wid_resp_upper;               /* 0x000060 */
-    u64                p_wid_resp_lower;               /* 0x000068 */
-    #define p_wid_resp p_wid_resp_lower
-    u64                p_wid_tst_pin_ctrl;             /* 0x000070 */
-    u64                p_wid_addr_lkerr;               /* 0x000078 */
-
-    /* 0x000080-0x00008F -- PMU & MAP */
-    u64                p_dir_map;                      /* 0x000080 */
-    u64                _pad_000088;                    /* 0x000088 */
-
-    /* 0x000090-0x00009F -- SSRAM */
-    u64                p_map_fault;                    /* 0x000090 */
-    u64                _pad_000098;                    /* 0x000098 */
-
-    /* 0x0000A0-0x0000AF -- Arbitration */
-    u64                p_arb;                          /* 0x0000A0 */
-    u64                _pad_0000A8;                    /* 0x0000A8 */
-
-    /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */
-    u64                p_ate_parity_err;               /* 0x0000B0 */
-    u64                _pad_0000B8;                    /* 0x0000B8 */
-
-    /* 0x0000C0-0x0000FF -- PCI/GIO */
-    u64                p_bus_timeout;                  /* 0x0000C0 */
-    u64                p_pci_cfg;                      /* 0x0000C8 */
-    u64                p_pci_err_upper;                /* 0x0000D0 */
-    u64                p_pci_err_lower;                /* 0x0000D8 */
-    #define p_pci_err p_pci_err_lower
-    u64                _pad_0000E0[4];                 /* 0x0000{E0..F8} */
-
-    /* 0x000100-0x0001FF -- Interrupt */
-    u64                p_int_status;                   /* 0x000100 */
-    u64                p_int_enable;                   /* 0x000108 */
-    u64                p_int_rst_stat;                 /* 0x000110 */
-    u64                p_int_mode;                     /* 0x000118 */
-    u64                p_int_device;                   /* 0x000120 */
-    u64                p_int_host_err;                 /* 0x000128 */
-    u64                p_int_addr[8];                  /* 0x0001{30,,,68} */
-    u64                p_err_int_view;                 /* 0x000170 */
-    u64                p_mult_int;                     /* 0x000178 */
-    u64                p_force_always[8];              /* 0x0001{80,,,B8} */
-    u64                p_force_pin[8];                 /* 0x0001{C0,,,F8} */
-
-    /* 0x000200-0x000298 -- Device */
-    u64                p_device[4];                    /* 0x0002{00,,,18} */
-    u64                _pad_000220[4];                 /* 0x0002{20,,,38} */
-    u64                p_wr_req_buf[4];                /* 0x0002{40,,,58} */
-    u64                _pad_000260[4];                 /* 0x0002{60,,,78} */
-    u64                p_rrb_map[2];                   /* 0x0002{80,,,88} */
-    #define p_even_resp p_rrb_map[0]                   /* 0x000280 */
-    #define p_odd_resp  p_rrb_map[1]                   /* 0x000288 */
-    u64                p_resp_status;                  /* 0x000290 */
-    u64                p_resp_clear;                   /* 0x000298 */
-
-    u64                _pad_0002A0[12];                /* 0x0002{A0..F8} */
-
-    /* 0x000300-0x0003F8 -- Buffer Address Match Registers */
-    struct {
-       u64     upper;                          /* 0x0003{00,,,F0} */
-       u64     lower;                          /* 0x0003{08,,,F8} */
-    } p_buf_addr_match[16];
-
-    /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */
-    struct {
-       u64     flush_w_touch;                  /* 0x000{400,,,5C0} */
-       u64     flush_wo_touch;                 /* 0x000{408,,,5C8} */
-       u64     inflight;                       /* 0x000{410,,,5D0} */
-       u64     prefetch;                       /* 0x000{418,,,5D8} */
-       u64     total_pci_retry;                /* 0x000{420,,,5E0} */
-       u64     max_pci_retry;                  /* 0x000{428,,,5E8} */
-       u64     max_latency;                    /* 0x000{430,,,5F0} */
-       u64     clear_all;                      /* 0x000{438,,,5F8} */
-    } p_buf_count[8];
-
-
-    /* 0x000600-0x0009FF -- PCI/X registers */
-    u64                p_pcix_bus_err_addr;            /* 0x000600 */
-    u64                p_pcix_bus_err_attr;            /* 0x000608 */
-    u64                p_pcix_bus_err_data;            /* 0x000610 */
-    u64                p_pcix_pio_split_addr;          /* 0x000618 */
-    u64                p_pcix_pio_split_attr;          /* 0x000620 */
-    u64                p_pcix_dma_req_err_attr;        /* 0x000628 */
-    u64                p_pcix_dma_req_err_addr;        /* 0x000630 */
-    u64                p_pcix_timeout;                 /* 0x000638 */
-
-    u64                _pad_000640[120];               /* 0x000{640,,,9F8} */
-
-    /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */
-    struct {
-       u64     p_buf_addr;                     /* 0x000{A00,,,AF0} */
-       u64     p_buf_attr;                     /* 0X000{A08,,,AF8} */
-    } p_pcix_read_buf_64[16];
-
-    struct {
-       u64     p_buf_addr;                     /* 0x000{B00,,,BE0} */
-       u64     p_buf_attr;                     /* 0x000{B08,,,BE8} */
-       u64     p_buf_valid;                    /* 0x000{B10,,,BF0} */
-       u64     __pad1;                         /* 0x000{B18,,,BF8} */
-    } p_pcix_write_buf_64[8];
-
-    /* End of Local Registers -- Start of Address Map space */
-
-    char               _pad_000c00[0x010000 - 0x000c00];
-
-    /* 0x010000-0x011fff -- Internal ATE RAM (Auto Parity Generation) */
-    u64                p_int_ate_ram[1024];            /* 0x010000-0x011fff */
-
-    /* 0x012000-0x013fff -- Internal ATE RAM (Manual Parity Generation) */
-    u64                p_int_ate_ram_mp[1024];         /* 0x012000-0x013fff */
-
-    char               _pad_014000[0x18000 - 0x014000];
-
-    /* 0x18000-0x197F8 -- PIC Write Request Ram */
-    u64                p_wr_req_lower[256];            /* 0x18000 - 0x187F8 */
-    u64                p_wr_req_upper[256];            /* 0x18800 - 0x18FF8 */
-    u64                p_wr_req_parity[256];           /* 0x19000 - 0x197F8 */
-
-    char               _pad_019800[0x20000 - 0x019800];
-
-    /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */
-    union {
-       u8              c[0x1000 / 1];                  /* 0x02{0000,,,7FFF} */
-       u16     s[0x1000 / 2];                  /* 0x02{0000,,,7FFF} */
-       u32     l[0x1000 / 4];                  /* 0x02{0000,,,7FFF} */
-       u64     d[0x1000 / 8];                  /* 0x02{0000,,,7FFF} */
-       union {
-           u8  c[0x100 / 1];
-           u16 s[0x100 / 2];
-           u32 l[0x100 / 4];
-           u64 d[0x100 / 8];
-       } f[8];
-    } p_type0_cfg_dev[8];                              /* 0x02{0000,,,7FFF} */
-
-    /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */
-    union {
-       u8              c[0x1000 / 1];                  /* 0x028000-0x029000 */
-       u16     s[0x1000 / 2];                  /* 0x028000-0x029000 */
-       u32     l[0x1000 / 4];                  /* 0x028000-0x029000 */
-       u64     d[0x1000 / 8];                  /* 0x028000-0x029000 */
-       union {
-           u8  c[0x100 / 1];
-           u16 s[0x100 / 2];
-           u32 l[0x100 / 4];
-           u64 d[0x100 / 8];
-       } f[8];
-    } p_type1_cfg;                                     /* 0x028000-0x029000 */
-
-    char               _pad_029000[0x030000-0x029000];
-
-    /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */
-    union {
-       u8              c[8 / 1];
-       u16     s[8 / 2];
-       u32     l[8 / 4];
-       u64     d[8 / 8];
-    } p_pci_iack;                                      /* 0x030000-0x030007 */
-
-    char               _pad_030007[0x040000-0x030008];
-
-    /* 0x040000-0x030007 -- PCIX Special Cycle */
-    union {
-       u8              c[8 / 1];
-       u16     s[8 / 2];
-       u32     l[8 / 4];
-       u64     d[8 / 8];
-    } p_pcix_cycle;                                    /* 0x040000-0x040007 */
-};
-
-#endif                          /* _ASM_IA64_SN_PCI_PIC_H */
diff --git a/arch/ia64/include/asm/sn/rw_mmr.h b/arch/ia64/include/asm/sn/rw_mmr.h
deleted file mode 100644 (file)
index 2d78f4c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2002-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-#ifndef _ASM_IA64_SN_RW_MMR_H
-#define _ASM_IA64_SN_RW_MMR_H
-
-
-/*
- * This file that access MMRs via uncached physical addresses.
- *     pio_phys_read_mmr  - read an MMR
- *     pio_phys_write_mmr - write an MMR
- *     pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0
- *             Second MMR will be skipped if address is NULL
- *
- * Addresses passed to these routines should be uncached physical addresses
- * ie., 0x80000....
- */
-
-
-extern long pio_phys_read_mmr(volatile long *mmr); 
-extern void pio_phys_write_mmr(volatile long *mmr, long val);
-extern void pio_atomic_phys_write_mmrs(volatile long *mmr1, long val1, volatile long *mmr2, long val2); 
-
-#endif /* _ASM_IA64_SN_RW_MMR_H */
diff --git a/arch/ia64/include/asm/sn/shub_mmr.h b/arch/ia64/include/asm/sn/shub_mmr.h
deleted file mode 100644 (file)
index a84d870..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2001-2005 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_SHUB_MMR_H
-#define _ASM_IA64_SN_SHUB_MMR_H
-
-/* ==================================================================== */
-/*                        Register "SH_IPI_INT"                         */
-/*               SHub Inter-Processor Interrupt Registers               */
-/* ==================================================================== */
-#define SH1_IPI_INT                    __IA64_UL_CONST(0x0000000110000380)
-#define SH2_IPI_INT                    __IA64_UL_CONST(0x0000000010000380)
-
-/*   SH_IPI_INT_TYPE                                                    */
-/*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_IPI_INT_TYPE_SHFT                           0
-#define SH_IPI_INT_TYPE_MASK           __IA64_UL_CONST(0x0000000000000007)
-
-/*   SH_IPI_INT_AGT                                                     */
-/*   Description:  Agent, must be 0 for SHub                            */
-#define SH_IPI_INT_AGT_SHFT                            3
-#define SH_IPI_INT_AGT_MASK            __IA64_UL_CONST(0x0000000000000008)
-
-/*   SH_IPI_INT_PID                                                     */
-/*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_IPI_INT_PID_SHFT                            4
-#define SH_IPI_INT_PID_MASK            __IA64_UL_CONST(0x00000000000ffff0)
-
-/*   SH_IPI_INT_BASE                                                    */
-/*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_IPI_INT_BASE_SHFT                           21
-#define SH_IPI_INT_BASE_MASK           __IA64_UL_CONST(0x0003ffffffe00000)
-
-/*   SH_IPI_INT_IDX                                                     */
-/*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_IPI_INT_IDX_SHFT                            52
-#define SH_IPI_INT_IDX_MASK            __IA64_UL_CONST(0x0ff0000000000000)
-
-/*   SH_IPI_INT_SEND                                                    */
-/*   Description:  Send Interrupt Message to PI, This generates a puls  */
-#define SH_IPI_INT_SEND_SHFT                           63
-#define SH_IPI_INT_SEND_MASK           __IA64_UL_CONST(0x8000000000000000)
-
-/* ==================================================================== */
-/*                     Register "SH_EVENT_OCCURRED"                     */
-/*                    SHub Interrupt Event Occurred                     */
-/* ==================================================================== */
-#define SH1_EVENT_OCCURRED             __IA64_UL_CONST(0x0000000110010000)
-#define SH1_EVENT_OCCURRED_ALIAS       __IA64_UL_CONST(0x0000000110010008)
-#define SH2_EVENT_OCCURRED             __IA64_UL_CONST(0x0000000010010000)
-#define SH2_EVENT_OCCURRED_ALIAS       __IA64_UL_CONST(0x0000000010010008)
-
-/* ==================================================================== */
-/*                     Register "SH_PI_CAM_CONTROL"                     */
-/*                      CRB CAM MMR Access Control                      */
-/* ==================================================================== */
-#define SH1_PI_CAM_CONTROL             __IA64_UL_CONST(0x0000000120050300)
-
-/* ==================================================================== */
-/*                        Register "SH_SHUB_ID"                         */
-/*                            SHub ID Number                            */
-/* ==================================================================== */
-#define SH1_SHUB_ID                    __IA64_UL_CONST(0x0000000110060580)
-#define SH1_SHUB_ID_REVISION_SHFT                      28
-#define SH1_SHUB_ID_REVISION_MASK      __IA64_UL_CONST(0x00000000f0000000)
-
-/* ==================================================================== */
-/*                          Register "SH_RTC"                           */
-/*                           Real-time Clock                            */
-/* ==================================================================== */
-#define SH1_RTC                                __IA64_UL_CONST(0x00000001101c0000)
-#define SH2_RTC                                __IA64_UL_CONST(0x00000002101c0000)
-#define SH_RTC_MASK                    __IA64_UL_CONST(0x007fffffffffffff)
-
-/* ==================================================================== */
-/*                   Register "SH_PIO_WRITE_STATUS_0|1"                 */
-/*                      PIO Write Status for CPU 0 & 1                  */
-/* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0         __IA64_UL_CONST(0x0000000120070200)
-#define SH1_PIO_WRITE_STATUS_1         __IA64_UL_CONST(0x0000000120070280)
-#define SH2_PIO_WRITE_STATUS_0         __IA64_UL_CONST(0x0000000020070200)
-#define SH2_PIO_WRITE_STATUS_1         __IA64_UL_CONST(0x0000000020070280)
-#define SH2_PIO_WRITE_STATUS_2         __IA64_UL_CONST(0x0000000020070300)
-#define SH2_PIO_WRITE_STATUS_3         __IA64_UL_CONST(0x0000000020070380)
-
-/*   SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK                               */
-/*   Description:  Deadlock response detected                           */
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT                1
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK \
-                                       __IA64_UL_CONST(0x0000000000000002)
-
-/*   SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT                          */
-/*   Description:  Count of currently pending PIO writes                */
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT   56
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK \
-                                       __IA64_UL_CONST(0x3f00000000000000)
-
-/* ==================================================================== */
-/*                Register "SH_PIO_WRITE_STATUS_0_ALIAS"                */
-/* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0_ALIAS   __IA64_UL_CONST(0x0000000120070208)
-#define SH2_PIO_WRITE_STATUS_0_ALIAS   __IA64_UL_CONST(0x0000000020070208)
-
-/* ==================================================================== */
-/*                     Register "SH_EVENT_OCCURRED"                     */
-/*                    SHub Interrupt Event Occurred                     */
-/* ==================================================================== */
-/*   SH_EVENT_OCCURRED_UART_INT                                         */
-/*   Description:  Pending Junk Bus UART Interrupt                      */
-#define SH_EVENT_OCCURRED_UART_INT_SHFT                        20
-#define SH_EVENT_OCCURRED_UART_INT_MASK        __IA64_UL_CONST(0x0000000000100000)
-
-/*   SH_EVENT_OCCURRED_IPI_INT                                          */
-/*   Description:  Pending IPI Interrupt                                */
-#define SH_EVENT_OCCURRED_IPI_INT_SHFT                 28
-#define SH_EVENT_OCCURRED_IPI_INT_MASK __IA64_UL_CONST(0x0000000010000000)
-
-/*   SH_EVENT_OCCURRED_II_INT0                                          */
-/*   Description:  Pending II 0 Interrupt                               */
-#define SH_EVENT_OCCURRED_II_INT0_SHFT                 29
-#define SH_EVENT_OCCURRED_II_INT0_MASK __IA64_UL_CONST(0x0000000020000000)
-
-/*   SH_EVENT_OCCURRED_II_INT1                                          */
-/*   Description:  Pending II 1 Interrupt                               */
-#define SH_EVENT_OCCURRED_II_INT1_SHFT                 30
-#define SH_EVENT_OCCURRED_II_INT1_MASK __IA64_UL_CONST(0x0000000040000000)
-
-/*   SH2_EVENT_OCCURRED_EXTIO_INT2                                      */
-/*   Description:  Pending SHUB 2 EXT IO INT2                           */
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT             33
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK __IA64_UL_CONST(0x0000000200000000)
-
-/*   SH2_EVENT_OCCURRED_EXTIO_INT3                                      */
-/*   Description:  Pending SHUB 2 EXT IO INT3                           */
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT             34
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK __IA64_UL_CONST(0x0000000400000000)
-
-#define SH_ALL_INT_MASK \
-       (SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \
-        SH_EVENT_OCCURRED_II_INT0_MASK | SH_EVENT_OCCURRED_II_INT1_MASK | \
-        SH_EVENT_OCCURRED_II_INT1_MASK | SH2_EVENT_OCCURRED_EXTIO_INT2_MASK | \
-        SH2_EVENT_OCCURRED_EXTIO_INT3_MASK)
-
-
-/* ==================================================================== */
-/*                         LEDS                                         */
-/* ==================================================================== */
-#define SH1_REAL_JUNK_BUS_LED0                 0x7fed00000UL
-#define SH1_REAL_JUNK_BUS_LED1                 0x7fed10000UL
-#define SH1_REAL_JUNK_BUS_LED2                 0x7fed20000UL
-#define SH1_REAL_JUNK_BUS_LED3                 0x7fed30000UL
-
-#define SH2_REAL_JUNK_BUS_LED0                 0xf0000000UL
-#define SH2_REAL_JUNK_BUS_LED1                 0xf0010000UL
-#define SH2_REAL_JUNK_BUS_LED2                 0xf0020000UL
-#define SH2_REAL_JUNK_BUS_LED3                 0xf0030000UL
-
-/* ==================================================================== */
-/*                         Register "SH1_PTC_0"                         */
-/*       Puge Translation Cache Message Configuration Information       */
-/* ==================================================================== */
-#define SH1_PTC_0                      __IA64_UL_CONST(0x00000001101a0000)
-
-/*   SH1_PTC_0_A                                                        */
-/*   Description:  Type                                                 */
-#define SH1_PTC_0_A_SHFT                               0
-
-/*   SH1_PTC_0_PS                                                       */
-/*   Description:  Page Size                                            */
-#define SH1_PTC_0_PS_SHFT                              2
-
-/*   SH1_PTC_0_RID                                                      */
-/*   Description:  Region ID                                            */
-#define SH1_PTC_0_RID_SHFT                             8
-
-/*   SH1_PTC_0_START                                                    */
-/*   Description:  Start                                                */
-#define SH1_PTC_0_START_SHFT                           63
-
-/* ==================================================================== */
-/*                         Register "SH1_PTC_1"                         */
-/*       Puge Translation Cache Message Configuration Information       */
-/* ==================================================================== */
-#define SH1_PTC_1                      __IA64_UL_CONST(0x00000001101a0080)
-
-/*   SH1_PTC_1_START                                                    */
-/*   Description:  PTC_1 Start                                          */
-#define SH1_PTC_1_START_SHFT                           63
-
-/* ==================================================================== */
-/*                         Register "SH2_PTC"                           */
-/*       Puge Translation Cache Message Configuration Information       */
-/* ==================================================================== */
-#define SH2_PTC                                __IA64_UL_CONST(0x0000000170000000)
-
-/*   SH2_PTC_A                                                          */
-/*   Description:  Type                                                 */
-#define SH2_PTC_A_SHFT                                 0
-
-/*   SH2_PTC_PS                                                         */
-/*   Description:  Page Size                                            */
-#define SH2_PTC_PS_SHFT                                        2
-
-/*   SH2_PTC_RID                                                      */
-/*   Description:  Region ID                                            */
-#define SH2_PTC_RID_SHFT                               4
-
-/*   SH2_PTC_START                                                      */
-/*   Description:  Start                                                */
-#define SH2_PTC_START_SHFT                             63
-
-/*   SH2_PTC_ADDR_RID                                                   */
-/*   Description:  Region ID                                            */
-#define SH2_PTC_ADDR_SHFT                              4
-#define SH2_PTC_ADDR_MASK              __IA64_UL_CONST(0x1ffffffffffff000)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC1_INT_CONFIG"                     */
-/*                SHub RTC 1 Interrupt Config Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC1_INT_CONFIG            __IA64_UL_CONST(0x0000000110001480)
-#define SH2_RTC1_INT_CONFIG            __IA64_UL_CONST(0x0000000010001480)
-#define SH_RTC1_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
-#define SH_RTC1_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC1_INT_CONFIG_TYPE                                            */
-/*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC1_INT_CONFIG_TYPE_SHFT                   0
-#define SH_RTC1_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
-
-/*   SH_RTC1_INT_CONFIG_AGT                                             */
-/*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC1_INT_CONFIG_AGT_SHFT                    3
-#define SH_RTC1_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
-
-/*   SH_RTC1_INT_CONFIG_PID                                             */
-/*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC1_INT_CONFIG_PID_SHFT                    4
-#define SH_RTC1_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
-
-/*   SH_RTC1_INT_CONFIG_BASE                                            */
-/*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC1_INT_CONFIG_BASE_SHFT                   21
-#define SH_RTC1_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
-
-/*   SH_RTC1_INT_CONFIG_IDX                                             */
-/*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC1_INT_CONFIG_IDX_SHFT                    52
-#define SH_RTC1_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC1_INT_ENABLE"                     */
-/*                SHub RTC 1 Interrupt Enable Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC1_INT_ENABLE            __IA64_UL_CONST(0x0000000110001500)
-#define SH2_RTC1_INT_ENABLE            __IA64_UL_CONST(0x0000000010001500)
-#define SH_RTC1_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
-#define SH_RTC1_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC1_INT_ENABLE_RTC1_ENABLE                                     */
-/*   Description:  Enable RTC 1 Interrupt                               */
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT            0
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK \
-                                       __IA64_UL_CONST(0x0000000000000001)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC2_INT_CONFIG"                     */
-/*                SHub RTC 2 Interrupt Config Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC2_INT_CONFIG            __IA64_UL_CONST(0x0000000110001580)
-#define SH2_RTC2_INT_CONFIG            __IA64_UL_CONST(0x0000000010001580)
-#define SH_RTC2_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
-#define SH_RTC2_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC2_INT_CONFIG_TYPE                                            */
-/*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC2_INT_CONFIG_TYPE_SHFT                   0
-#define SH_RTC2_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
-
-/*   SH_RTC2_INT_CONFIG_AGT                                             */
-/*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC2_INT_CONFIG_AGT_SHFT                    3
-#define SH_RTC2_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
-
-/*   SH_RTC2_INT_CONFIG_PID                                             */
-/*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC2_INT_CONFIG_PID_SHFT                    4
-#define SH_RTC2_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
-
-/*   SH_RTC2_INT_CONFIG_BASE                                            */
-/*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC2_INT_CONFIG_BASE_SHFT                   21
-#define SH_RTC2_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
-
-/*   SH_RTC2_INT_CONFIG_IDX                                             */
-/*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC2_INT_CONFIG_IDX_SHFT                    52
-#define SH_RTC2_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC2_INT_ENABLE"                     */
-/*                SHub RTC 2 Interrupt Enable Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC2_INT_ENABLE            __IA64_UL_CONST(0x0000000110001600)
-#define SH2_RTC2_INT_ENABLE            __IA64_UL_CONST(0x0000000010001600)
-#define SH_RTC2_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
-#define SH_RTC2_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC2_INT_ENABLE_RTC2_ENABLE                                     */
-/*   Description:  Enable RTC 2 Interrupt                               */
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT            0
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK \
-                                       __IA64_UL_CONST(0x0000000000000001)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC3_INT_CONFIG"                     */
-/*                SHub RTC 3 Interrupt Config Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC3_INT_CONFIG            __IA64_UL_CONST(0x0000000110001680)
-#define SH2_RTC3_INT_CONFIG            __IA64_UL_CONST(0x0000000010001680)
-#define SH_RTC3_INT_CONFIG_MASK                __IA64_UL_CONST(0x0ff3ffffffefffff)
-#define SH_RTC3_INT_CONFIG_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC3_INT_CONFIG_TYPE                                            */
-/*   Description:  Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT       */
-#define SH_RTC3_INT_CONFIG_TYPE_SHFT                   0
-#define SH_RTC3_INT_CONFIG_TYPE_MASK   __IA64_UL_CONST(0x0000000000000007)
-
-/*   SH_RTC3_INT_CONFIG_AGT                                             */
-/*   Description:  Agent, must be 0 for SHub                            */
-#define SH_RTC3_INT_CONFIG_AGT_SHFT                    3
-#define SH_RTC3_INT_CONFIG_AGT_MASK    __IA64_UL_CONST(0x0000000000000008)
-
-/*   SH_RTC3_INT_CONFIG_PID                                             */
-/*   Description:  Processor ID, same setting as on targeted McKinley  */
-#define SH_RTC3_INT_CONFIG_PID_SHFT                    4
-#define SH_RTC3_INT_CONFIG_PID_MASK    __IA64_UL_CONST(0x00000000000ffff0)
-
-/*   SH_RTC3_INT_CONFIG_BASE                                            */
-/*   Description:  Optional interrupt vector area, 2MB aligned          */
-#define SH_RTC3_INT_CONFIG_BASE_SHFT                   21
-#define SH_RTC3_INT_CONFIG_BASE_MASK   __IA64_UL_CONST(0x0003ffffffe00000)
-
-/*   SH_RTC3_INT_CONFIG_IDX                                             */
-/*   Description:  Targeted McKinley interrupt vector                   */
-#define SH_RTC3_INT_CONFIG_IDX_SHFT                    52
-#define SH_RTC3_INT_CONFIG_IDX_MASK    __IA64_UL_CONST(0x0ff0000000000000)
-
-/* ==================================================================== */
-/*                    Register "SH_RTC3_INT_ENABLE"                     */
-/*                SHub RTC 3 Interrupt Enable Registers                 */
-/* ==================================================================== */
-
-#define SH1_RTC3_INT_ENABLE            __IA64_UL_CONST(0x0000000110001700)
-#define SH2_RTC3_INT_ENABLE            __IA64_UL_CONST(0x0000000010001700)
-#define SH_RTC3_INT_ENABLE_MASK                __IA64_UL_CONST(0x0000000000000001)
-#define SH_RTC3_INT_ENABLE_INIT                __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_RTC3_INT_ENABLE_RTC3_ENABLE                                     */
-/*   Description:  Enable RTC 3 Interrupt                               */
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT            0
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK \
-                                       __IA64_UL_CONST(0x0000000000000001)
-
-/*   SH_EVENT_OCCURRED_RTC1_INT                                         */
-/*   Description:  Pending RTC 1 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC1_INT_SHFT                        24
-#define SH_EVENT_OCCURRED_RTC1_INT_MASK        __IA64_UL_CONST(0x0000000001000000)
-
-/*   SH_EVENT_OCCURRED_RTC2_INT                                         */
-/*   Description:  Pending RTC 2 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC2_INT_SHFT                        25
-#define SH_EVENT_OCCURRED_RTC2_INT_MASK        __IA64_UL_CONST(0x0000000002000000)
-
-/*   SH_EVENT_OCCURRED_RTC3_INT                                         */
-/*   Description:  Pending RTC 3 Interrupt                              */
-#define SH_EVENT_OCCURRED_RTC3_INT_SHFT                        26
-#define SH_EVENT_OCCURRED_RTC3_INT_MASK        __IA64_UL_CONST(0x0000000004000000)
-
-/* ==================================================================== */
-/*                       Register "SH_IPI_ACCESS"                       */
-/*                 CPU interrupt Access Permission Bits                 */
-/* ==================================================================== */
-
-#define SH1_IPI_ACCESS                 __IA64_UL_CONST(0x0000000110060480)
-#define SH2_IPI_ACCESS0                        __IA64_UL_CONST(0x0000000010060c00)
-#define SH2_IPI_ACCESS1                        __IA64_UL_CONST(0x0000000010060c80)
-#define SH2_IPI_ACCESS2                        __IA64_UL_CONST(0x0000000010060d00)
-#define SH2_IPI_ACCESS3                        __IA64_UL_CONST(0x0000000010060d80)
-
-/* ==================================================================== */
-/*                        Register "SH_INT_CMPB"                        */
-/*                  RTC Compare Value for Processor B                   */
-/* ==================================================================== */
-
-#define SH1_INT_CMPB                   __IA64_UL_CONST(0x00000001101b0080)
-#define SH2_INT_CMPB                   __IA64_UL_CONST(0x00000000101b0080)
-#define SH_INT_CMPB_MASK               __IA64_UL_CONST(0x007fffffffffffff)
-#define SH_INT_CMPB_INIT               __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_INT_CMPB_REAL_TIME_CMPB                                         */
-/*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT                        0
-#define SH_INT_CMPB_REAL_TIME_CMPB_MASK        __IA64_UL_CONST(0x007fffffffffffff)
-
-/* ==================================================================== */
-/*                        Register "SH_INT_CMPC"                        */
-/*                  RTC Compare Value for Processor C                   */
-/* ==================================================================== */
-
-#define SH1_INT_CMPC                   __IA64_UL_CONST(0x00000001101b0100)
-#define SH2_INT_CMPC                   __IA64_UL_CONST(0x00000000101b0100)
-#define SH_INT_CMPC_MASK               __IA64_UL_CONST(0x007fffffffffffff)
-#define SH_INT_CMPC_INIT               __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_INT_CMPC_REAL_TIME_CMPC                                         */
-/*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT                        0
-#define SH_INT_CMPC_REAL_TIME_CMPC_MASK        __IA64_UL_CONST(0x007fffffffffffff)
-
-/* ==================================================================== */
-/*                        Register "SH_INT_CMPD"                        */
-/*                  RTC Compare Value for Processor D                   */
-/* ==================================================================== */
-
-#define SH1_INT_CMPD                   __IA64_UL_CONST(0x00000001101b0180)
-#define SH2_INT_CMPD                   __IA64_UL_CONST(0x00000000101b0180)
-#define SH_INT_CMPD_MASK               __IA64_UL_CONST(0x007fffffffffffff)
-#define SH_INT_CMPD_INIT               __IA64_UL_CONST(0x0000000000000000)
-
-/*   SH_INT_CMPD_REAL_TIME_CMPD                                         */
-/*   Description:  Real Time Clock Compare                              */
-#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT                        0
-#define SH_INT_CMPD_REAL_TIME_CMPD_MASK        __IA64_UL_CONST(0x007fffffffffffff)
-
-/* ==================================================================== */
-/*                Register "SH_MD_DQLP_MMR_DIR_PRIVEC0"                 */
-/*                      privilege vector for acc=0                      */
-/* ==================================================================== */
-#define SH1_MD_DQLP_MMR_DIR_PRIVEC0    __IA64_UL_CONST(0x0000000100030300)
-
-/* ==================================================================== */
-/*                Register "SH_MD_DQRP_MMR_DIR_PRIVEC0"                 */
-/*                      privilege vector for acc=0                      */
-/* ==================================================================== */
-#define SH1_MD_DQRP_MMR_DIR_PRIVEC0    __IA64_UL_CONST(0x0000000100050300)
-
-/* ==================================================================== */
-/* Some MMRs are functionally identical (or close enough) on both SHUB1 */
-/* and SHUB2 that it makes sense to define a geberic name for the MMR.  */
-/* It is acceptable to use (for example) SH_IPI_INT to reference the    */
-/* the IPI MMR. The value of SH_IPI_INT is determined at runtime based  */
-/* on the type of the SHUB. Do not use these #defines in performance    */
-/* critical code  or loops - there is a small performance penalty.      */
-/* ==================================================================== */
-#define shubmmr(a,b)           (is_shub2() ? a##2_##b : a##1_##b)
-
-#define SH_REAL_JUNK_BUS_LED0  shubmmr(SH, REAL_JUNK_BUS_LED0)
-#define SH_IPI_INT             shubmmr(SH, IPI_INT)
-#define SH_EVENT_OCCURRED      shubmmr(SH, EVENT_OCCURRED)
-#define SH_EVENT_OCCURRED_ALIAS        shubmmr(SH, EVENT_OCCURRED_ALIAS)
-#define SH_RTC                 shubmmr(SH, RTC)
-#define SH_RTC1_INT_CONFIG     shubmmr(SH, RTC1_INT_CONFIG)
-#define SH_RTC1_INT_ENABLE     shubmmr(SH, RTC1_INT_ENABLE)
-#define SH_RTC2_INT_CONFIG     shubmmr(SH, RTC2_INT_CONFIG)
-#define SH_RTC2_INT_ENABLE     shubmmr(SH, RTC2_INT_ENABLE)
-#define SH_RTC3_INT_CONFIG     shubmmr(SH, RTC3_INT_CONFIG)
-#define SH_RTC3_INT_ENABLE     shubmmr(SH, RTC3_INT_ENABLE)
-#define SH_INT_CMPB            shubmmr(SH, INT_CMPB)
-#define SH_INT_CMPC            shubmmr(SH, INT_CMPC)
-#define SH_INT_CMPD            shubmmr(SH, INT_CMPD)
-
-/* ========================================================================== */
-/*                        Register "SH2_BT_ENG_CSR_0"                         */
-/*                    Engine 0 Control and Status Register                    */
-/* ========================================================================== */
-
-#define SH2_BT_ENG_CSR_0               __IA64_UL_CONST(0x0000000030040000)
-#define SH2_BT_ENG_SRC_ADDR_0          __IA64_UL_CONST(0x0000000030040080)
-#define SH2_BT_ENG_DEST_ADDR_0         __IA64_UL_CONST(0x0000000030040100)
-#define SH2_BT_ENG_NOTIF_ADDR_0                __IA64_UL_CONST(0x0000000030040180)
-
-/* ========================================================================== */
-/*                       BTE interfaces 1-3                                   */
-/* ========================================================================== */
-
-#define SH2_BT_ENG_CSR_1               __IA64_UL_CONST(0x0000000030050000)
-#define SH2_BT_ENG_CSR_2               __IA64_UL_CONST(0x0000000030060000)
-#define SH2_BT_ENG_CSR_3               __IA64_UL_CONST(0x0000000030070000)
-
-#endif /* _ASM_IA64_SN_SHUB_MMR_H */
diff --git a/arch/ia64/include/asm/sn/shubio.h b/arch/ia64/include/asm/sn/shubio.h
deleted file mode 100644 (file)
index 8a1ec13..0000000
+++ /dev/null
@@ -1,3358 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_SHUBIO_H
-#define _ASM_IA64_SN_SHUBIO_H
-
-#define HUB_WIDGET_ID_MAX      0xf
-#define IIO_NUM_ITTES          7
-#define HUB_NUM_BIG_WINDOW     (IIO_NUM_ITTES - 1)
-
-#define                IIO_WID                 0x00400000      /* Crosstalk Widget Identification */
-                                                       /* This register is also accessible from
-                                                        * Crosstalk at address 0x0.  */
-#define                IIO_WSTAT               0x00400008      /* Crosstalk Widget Status */
-#define                IIO_WCR                 0x00400020      /* Crosstalk Widget Control Register */
-#define                IIO_ILAPR               0x00400100      /* IO Local Access Protection Register */
-#define                IIO_ILAPO               0x00400108      /* IO Local Access Protection Override */
-#define                IIO_IOWA                0x00400110      /* IO Outbound Widget Access */
-#define                IIO_IIWA                0x00400118      /* IO Inbound Widget Access */
-#define                IIO_IIDEM               0x00400120      /* IO Inbound Device Error Mask */
-#define                IIO_ILCSR               0x00400128      /* IO LLP Control and Status Register */
-#define                IIO_ILLR                0x00400130      /* IO LLP Log Register    */
-#define                IIO_IIDSR               0x00400138      /* IO Interrupt Destination */
-
-#define                IIO_IGFX0               0x00400140      /* IO Graphics Node-Widget Map 0 */
-#define                IIO_IGFX1               0x00400148      /* IO Graphics Node-Widget Map 1 */
-
-#define                IIO_ISCR0               0x00400150      /* IO Scratch Register 0 */
-#define                IIO_ISCR1               0x00400158      /* IO Scratch Register 1 */
-
-#define                IIO_ITTE1               0x00400160      /* IO Translation Table Entry 1 */
-#define                IIO_ITTE2               0x00400168      /* IO Translation Table Entry 2 */
-#define                IIO_ITTE3               0x00400170      /* IO Translation Table Entry 3 */
-#define                IIO_ITTE4               0x00400178      /* IO Translation Table Entry 4 */
-#define                IIO_ITTE5               0x00400180      /* IO Translation Table Entry 5 */
-#define                IIO_ITTE6               0x00400188      /* IO Translation Table Entry 6 */
-#define                IIO_ITTE7               0x00400190      /* IO Translation Table Entry 7 */
-
-#define                IIO_IPRB0               0x00400198      /* IO PRB Entry 0   */
-#define                IIO_IPRB8               0x004001A0      /* IO PRB Entry 8   */
-#define                IIO_IPRB9               0x004001A8      /* IO PRB Entry 9   */
-#define                IIO_IPRBA               0x004001B0      /* IO PRB Entry A   */
-#define                IIO_IPRBB               0x004001B8      /* IO PRB Entry B   */
-#define                IIO_IPRBC               0x004001C0      /* IO PRB Entry C   */
-#define                IIO_IPRBD               0x004001C8      /* IO PRB Entry D   */
-#define                IIO_IPRBE               0x004001D0      /* IO PRB Entry E   */
-#define                IIO_IPRBF               0x004001D8      /* IO PRB Entry F   */
-
-#define                IIO_IXCC                0x004001E0      /* IO Crosstalk Credit Count Timeout */
-#define                IIO_IMEM                0x004001E8      /* IO Miscellaneous Error Mask */
-#define                IIO_IXTT                0x004001F0      /* IO Crosstalk Timeout Threshold */
-#define                IIO_IECLR               0x004001F8      /* IO Error Clear Register */
-#define                IIO_IBCR                0x00400200      /* IO BTE Control Register */
-
-#define                IIO_IXSM                0x00400208      /* IO Crosstalk Spurious Message */
-#define                IIO_IXSS                0x00400210      /* IO Crosstalk Spurious Sideband */
-
-#define                IIO_ILCT                0x00400218      /* IO LLP Channel Test    */
-
-#define                IIO_IIEPH1              0x00400220      /* IO Incoming Error Packet Header, Part 1 */
-#define                IIO_IIEPH2              0x00400228      /* IO Incoming Error Packet Header, Part 2 */
-
-#define                IIO_ISLAPR              0x00400230      /* IO SXB Local Access Protection Regster */
-#define                IIO_ISLAPO              0x00400238      /* IO SXB Local Access Protection Override */
-
-#define                IIO_IWI                 0x00400240      /* IO Wrapper Interrupt Register */
-#define                IIO_IWEL                0x00400248      /* IO Wrapper Error Log Register */
-#define                IIO_IWC                 0x00400250      /* IO Wrapper Control Register */
-#define                IIO_IWS                 0x00400258      /* IO Wrapper Status Register */
-#define                IIO_IWEIM               0x00400260      /* IO Wrapper Error Interrupt Masking Register */
-
-#define                IIO_IPCA                0x00400300      /* IO PRB Counter Adjust */
-
-#define                IIO_IPRTE0_A            0x00400308      /* IO PIO Read Address Table Entry 0, Part A */
-#define                IIO_IPRTE1_A            0x00400310      /* IO PIO Read Address Table Entry 1, Part A */
-#define                IIO_IPRTE2_A            0x00400318      /* IO PIO Read Address Table Entry 2, Part A */
-#define                IIO_IPRTE3_A            0x00400320      /* IO PIO Read Address Table Entry 3, Part A */
-#define                IIO_IPRTE4_A            0x00400328      /* IO PIO Read Address Table Entry 4, Part A */
-#define                IIO_IPRTE5_A            0x00400330      /* IO PIO Read Address Table Entry 5, Part A */
-#define                IIO_IPRTE6_A            0x00400338      /* IO PIO Read Address Table Entry 6, Part A */
-#define                IIO_IPRTE7_A            0x00400340      /* IO PIO Read Address Table Entry 7, Part A */
-
-#define                IIO_IPRTE0_B            0x00400348      /* IO PIO Read Address Table Entry 0, Part B */
-#define                IIO_IPRTE1_B            0x00400350      /* IO PIO Read Address Table Entry 1, Part B */
-#define                IIO_IPRTE2_B            0x00400358      /* IO PIO Read Address Table Entry 2, Part B */
-#define                IIO_IPRTE3_B            0x00400360      /* IO PIO Read Address Table Entry 3, Part B */
-#define                IIO_IPRTE4_B            0x00400368      /* IO PIO Read Address Table Entry 4, Part B */
-#define                IIO_IPRTE5_B            0x00400370      /* IO PIO Read Address Table Entry 5, Part B */
-#define                IIO_IPRTE6_B            0x00400378      /* IO PIO Read Address Table Entry 6, Part B */
-#define                IIO_IPRTE7_B            0x00400380      /* IO PIO Read Address Table Entry 7, Part B */
-
-#define                IIO_IPDR                0x00400388      /* IO PIO Deallocation Register */
-#define                IIO_ICDR                0x00400390      /* IO CRB Entry Deallocation Register */
-#define                IIO_IFDR                0x00400398      /* IO IOQ FIFO Depth Register */
-#define                IIO_IIAP                0x004003A0      /* IO IIQ Arbitration Parameters */
-#define                IIO_ICMR                0x004003A8      /* IO CRB Management Register */
-#define                IIO_ICCR                0x004003B0      /* IO CRB Control Register */
-#define                IIO_ICTO                0x004003B8      /* IO CRB Timeout   */
-#define                IIO_ICTP                0x004003C0      /* IO CRB Timeout Prescalar */
-
-#define                IIO_ICRB0_A             0x00400400      /* IO CRB Entry 0_A */
-#define                IIO_ICRB0_B             0x00400408      /* IO CRB Entry 0_B */
-#define                IIO_ICRB0_C             0x00400410      /* IO CRB Entry 0_C */
-#define                IIO_ICRB0_D             0x00400418      /* IO CRB Entry 0_D */
-#define                IIO_ICRB0_E             0x00400420      /* IO CRB Entry 0_E */
-
-#define                IIO_ICRB1_A             0x00400430      /* IO CRB Entry 1_A */
-#define                IIO_ICRB1_B             0x00400438      /* IO CRB Entry 1_B */
-#define                IIO_ICRB1_C             0x00400440      /* IO CRB Entry 1_C */
-#define                IIO_ICRB1_D             0x00400448      /* IO CRB Entry 1_D */
-#define                IIO_ICRB1_E             0x00400450      /* IO CRB Entry 1_E */
-
-#define                IIO_ICRB2_A             0x00400460      /* IO CRB Entry 2_A */
-#define                IIO_ICRB2_B             0x00400468      /* IO CRB Entry 2_B */
-#define                IIO_ICRB2_C             0x00400470      /* IO CRB Entry 2_C */
-#define                IIO_ICRB2_D             0x00400478      /* IO CRB Entry 2_D */
-#define                IIO_ICRB2_E             0x00400480      /* IO CRB Entry 2_E */
-
-#define                IIO_ICRB3_A             0x00400490      /* IO CRB Entry 3_A */
-#define                IIO_ICRB3_B             0x00400498      /* IO CRB Entry 3_B */
-#define                IIO_ICRB3_C             0x004004a0      /* IO CRB Entry 3_C */
-#define                IIO_ICRB3_D             0x004004a8      /* IO CRB Entry 3_D */
-#define                IIO_ICRB3_E             0x004004b0      /* IO CRB Entry 3_E */
-
-#define                IIO_ICRB4_A             0x004004c0      /* IO CRB Entry 4_A */
-#define                IIO_ICRB4_B             0x004004c8      /* IO CRB Entry 4_B */
-#define                IIO_ICRB4_C             0x004004d0      /* IO CRB Entry 4_C */
-#define                IIO_ICRB4_D             0x004004d8      /* IO CRB Entry 4_D */
-#define                IIO_ICRB4_E             0x004004e0      /* IO CRB Entry 4_E */
-
-#define                IIO_ICRB5_A             0x004004f0      /* IO CRB Entry 5_A */
-#define                IIO_ICRB5_B             0x004004f8      /* IO CRB Entry 5_B */
-#define                IIO_ICRB5_C             0x00400500      /* IO CRB Entry 5_C */
-#define                IIO_ICRB5_D             0x00400508      /* IO CRB Entry 5_D */
-#define                IIO_ICRB5_E             0x00400510      /* IO CRB Entry 5_E */
-
-#define                IIO_ICRB6_A             0x00400520      /* IO CRB Entry 6_A */
-#define                IIO_ICRB6_B             0x00400528      /* IO CRB Entry 6_B */
-#define                IIO_ICRB6_C             0x00400530      /* IO CRB Entry 6_C */
-#define                IIO_ICRB6_D             0x00400538      /* IO CRB Entry 6_D */
-#define                IIO_ICRB6_E             0x00400540      /* IO CRB Entry 6_E */
-
-#define                IIO_ICRB7_A             0x00400550      /* IO CRB Entry 7_A */
-#define                IIO_ICRB7_B             0x00400558      /* IO CRB Entry 7_B */
-#define                IIO_ICRB7_C             0x00400560      /* IO CRB Entry 7_C */
-#define                IIO_ICRB7_D             0x00400568      /* IO CRB Entry 7_D */
-#define                IIO_ICRB7_E             0x00400570      /* IO CRB Entry 7_E */
-
-#define                IIO_ICRB8_A             0x00400580      /* IO CRB Entry 8_A */
-#define                IIO_ICRB8_B             0x00400588      /* IO CRB Entry 8_B */
-#define                IIO_ICRB8_C             0x00400590      /* IO CRB Entry 8_C */
-#define                IIO_ICRB8_D             0x00400598      /* IO CRB Entry 8_D */
-#define                IIO_ICRB8_E             0x004005a0      /* IO CRB Entry 8_E */
-
-#define                IIO_ICRB9_A             0x004005b0      /* IO CRB Entry 9_A */
-#define                IIO_ICRB9_B             0x004005b8      /* IO CRB Entry 9_B */
-#define                IIO_ICRB9_C             0x004005c0      /* IO CRB Entry 9_C */
-#define                IIO_ICRB9_D             0x004005c8      /* IO CRB Entry 9_D */
-#define                IIO_ICRB9_E             0x004005d0      /* IO CRB Entry 9_E */
-
-#define                IIO_ICRBA_A             0x004005e0      /* IO CRB Entry A_A */
-#define                IIO_ICRBA_B             0x004005e8      /* IO CRB Entry A_B */
-#define                IIO_ICRBA_C             0x004005f0      /* IO CRB Entry A_C */
-#define                IIO_ICRBA_D             0x004005f8      /* IO CRB Entry A_D */
-#define                IIO_ICRBA_E             0x00400600      /* IO CRB Entry A_E */
-
-#define                IIO_ICRBB_A             0x00400610      /* IO CRB Entry B_A */
-#define                IIO_ICRBB_B             0x00400618      /* IO CRB Entry B_B */
-#define                IIO_ICRBB_C             0x00400620      /* IO CRB Entry B_C */
-#define                IIO_ICRBB_D             0x00400628      /* IO CRB Entry B_D */
-#define                IIO_ICRBB_E             0x00400630      /* IO CRB Entry B_E */
-
-#define                IIO_ICRBC_A             0x00400640      /* IO CRB Entry C_A */
-#define                IIO_ICRBC_B             0x00400648      /* IO CRB Entry C_B */
-#define                IIO_ICRBC_C             0x00400650      /* IO CRB Entry C_C */
-#define                IIO_ICRBC_D             0x00400658      /* IO CRB Entry C_D */
-#define                IIO_ICRBC_E             0x00400660      /* IO CRB Entry C_E */
-
-#define                IIO_ICRBD_A             0x00400670      /* IO CRB Entry D_A */
-#define                IIO_ICRBD_B             0x00400678      /* IO CRB Entry D_B */
-#define                IIO_ICRBD_C             0x00400680      /* IO CRB Entry D_C */
-#define                IIO_ICRBD_D             0x00400688      /* IO CRB Entry D_D */
-#define                IIO_ICRBD_E             0x00400690      /* IO CRB Entry D_E */
-
-#define                IIO_ICRBE_A             0x004006a0      /* IO CRB Entry E_A */
-#define                IIO_ICRBE_B             0x004006a8      /* IO CRB Entry E_B */
-#define                IIO_ICRBE_C             0x004006b0      /* IO CRB Entry E_C */
-#define                IIO_ICRBE_D             0x004006b8      /* IO CRB Entry E_D */
-#define                IIO_ICRBE_E             0x004006c0      /* IO CRB Entry E_E */
-
-#define                IIO_ICSML               0x00400700      /* IO CRB Spurious Message Low */
-#define                IIO_ICSMM               0x00400708      /* IO CRB Spurious Message Middle */
-#define                IIO_ICSMH               0x00400710      /* IO CRB Spurious Message High */
-
-#define                IIO_IDBSS               0x00400718      /* IO Debug Submenu Select */
-
-#define                IIO_IBLS0               0x00410000      /* IO BTE Length Status 0 */
-#define                IIO_IBSA0               0x00410008      /* IO BTE Source Address 0 */
-#define                IIO_IBDA0               0x00410010      /* IO BTE Destination Address 0 */
-#define                IIO_IBCT0               0x00410018      /* IO BTE Control Terminate 0 */
-#define                IIO_IBNA0               0x00410020      /* IO BTE Notification Address 0 */
-#define                IIO_IBIA0               0x00410028      /* IO BTE Interrupt Address 0 */
-#define                IIO_IBLS1               0x00420000      /* IO BTE Length Status 1 */
-#define                IIO_IBSA1               0x00420008      /* IO BTE Source Address 1 */
-#define                IIO_IBDA1               0x00420010      /* IO BTE Destination Address 1 */
-#define                IIO_IBCT1               0x00420018      /* IO BTE Control Terminate 1 */
-#define                IIO_IBNA1               0x00420020      /* IO BTE Notification Address 1 */
-#define                IIO_IBIA1               0x00420028      /* IO BTE Interrupt Address 1 */
-
-#define                IIO_IPCR                0x00430000      /* IO Performance Control */
-#define                IIO_IPPR                0x00430008      /* IO Performance Profiling */
-
-/************************************************************************
- *                                                                     *
- * Description:  This register echoes some information from the         *
- * LB_REV_ID register. It is available through Crosstalk as described   *
- * above. The REV_NUM and MFG_NUM fields receive their values from      *
- * the REVISION and MANUFACTURER fields in the LB_REV_ID register.      *
- * The PART_NUM field's value is the Crosstalk device ID number that    *
- * Steve Miller assigned to the SHub chip.                              *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_wid_u {
-       u64 ii_wid_regval;
-       struct {
-               u64 w_rsvd_1:1;
-               u64 w_mfg_num:11;
-               u64 w_part_num:16;
-               u64 w_rev_num:4;
-               u64 w_rsvd:32;
-       } ii_wid_fld_s;
-} ii_wid_u_t;
-
-/************************************************************************
- *                                                                     *
- *  The fields in this register are set upon detection of an error      *
- * and cleared by various mechanisms, as explained in the               *
- * description.                                                         *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_wstat_u {
-       u64 ii_wstat_regval;
-       struct {
-               u64 w_pending:4;
-               u64 w_xt_crd_to:1;
-               u64 w_xt_tail_to:1;
-               u64 w_rsvd_3:3;
-               u64 w_tx_mx_rty:1;
-               u64 w_rsvd_2:6;
-               u64 w_llp_tx_cnt:8;
-               u64 w_rsvd_1:8;
-               u64 w_crazy:1;
-               u64 w_rsvd:31;
-       } ii_wstat_fld_s;
-} ii_wstat_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This is a read-write enabled register. It controls     *
- * various aspects of the Crosstalk flow control.                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_wcr_u {
-       u64 ii_wcr_regval;
-       struct {
-               u64 w_wid:4;
-               u64 w_tag:1;
-               u64 w_rsvd_1:8;
-               u64 w_dst_crd:3;
-               u64 w_f_bad_pkt:1;
-               u64 w_dir_con:1;
-               u64 w_e_thresh:5;
-               u64 w_rsvd:41;
-       } ii_wcr_fld_s;
-} ii_wcr_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register's value is a bit vector that guards      *
- * access to local registers within the II as well as to external       *
- * Crosstalk widgets. Each bit in the register corresponds to a         *
- * particular region in the system; a region consists of one, two or    *
- * four nodes (depending on the value of the REGION_SIZE field in the   *
- * LB_REV_ID register, which is documented in Section 8.3.1.1). The     *
- * protection provided by this register applies to PIO read             *
- * operations as well as PIO write operations. The II will perform a    *
- * PIO read or write request only if the bit for the requestor's        *
- * region is set; otherwise, the II will not perform the requested      *
- * operation and will return an error response. When a PIO read or      *
- * write request targets an external Crosstalk widget, then not only    *
- * must the bit for the requestor's region be set in the ILAPR, but     *
- * also the target widget's bit in the IOWA register must be set in     *
- * order for the II to perform the requested operation; otherwise,      *
- * the II will return an error response. Hence, the protection          *
- * provided by the IOWA register supplements the protection provided    *
- * by the ILAPR for requests that target external Crosstalk widgets.    *
- * This register itself can be accessed only by the nodes whose         *
- * region ID bits are enabled in this same register. It can also be     *
- * accessed through the IAlias space by the local processors.           *
- * The reset value of this register allows access by all nodes.         *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ilapr_u {
-       u64 ii_ilapr_regval;
-       struct {
-               u64 i_region:64;
-       } ii_ilapr_fld_s;
-} ii_ilapr_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  A write to this register of the 64-bit value           *
- * "SGIrules" in ASCII, will cause the bit in the ILAPR register        *
- * corresponding to the region of the requestor to be set (allow        *
- * access). A write of any other value will be ignored. Access          *
- * protection for this register is "SGIrules".                          *
- * This register can also be accessed through the IAlias space.         *
- * However, this access will not change the access permissions in the   *
- * ILAPR.                                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ilapo_u {
-       u64 ii_ilapo_regval;
-       struct {
-               u64 i_io_ovrride:64;
-       } ii_ilapo_fld_s;
-} ii_ilapo_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register qualifies all the PIO and Graphics writes launched    *
- * from the SHUB towards a widget.                                      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iowa_u {
-       u64 ii_iowa_regval;
-       struct {
-               u64 i_w0_oac:1;
-               u64 i_rsvd_1:7;
-               u64 i_wx_oac:8;
-               u64 i_rsvd:48;
-       } ii_iowa_fld_s;
-} ii_iowa_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register qualifies all the requests launched      *
- * from a widget towards the Shub. This register is intended to be      *
- * used by software in case of misbehaving widgets.                     *
- *                                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iiwa_u {
-       u64 ii_iiwa_regval;
-       struct {
-               u64 i_w0_iac:1;
-               u64 i_rsvd_1:7;
-               u64 i_wx_iac:8;
-               u64 i_rsvd:48;
-       } ii_iiwa_fld_s;
-} ii_iiwa_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register qualifies all the operations launched    *
- * from a widget towards the SHub. It allows individual access          *
- * control for up to 8 devices per widget. A device refers to           *
- * individual DMA master hosted by a widget.                            *
- * The bits in each field of this register are cleared by the Shub      *
- * upon detection of an error which requires the device to be           *
- * disabled. These fields assume that 0=TNUM=7 (i.e., Bridge-centric    *
- * Crosstalk). Whether or not a device has access rights to this        *
- * Shub is determined by an AND of the device enable bit in the         *
- * appropriate field of this register and the corresponding bit in      *
- * the Wx_IAC field (for the widget which this device belongs to).      *
- * The bits in this field are set by writing a 1 to them. Incoming      *
- * replies from Crosstalk are not subject to this access control        *
- * mechanism.                                                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iidem_u {
-       u64 ii_iidem_regval;
-       struct {
-               u64 i_w8_dxs:8;
-               u64 i_w9_dxs:8;
-               u64 i_wa_dxs:8;
-               u64 i_wb_dxs:8;
-               u64 i_wc_dxs:8;
-               u64 i_wd_dxs:8;
-               u64 i_we_dxs:8;
-               u64 i_wf_dxs:8;
-       } ii_iidem_fld_s;
-} ii_iidem_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the various programmable fields necessary    *
- * for controlling and observing the LLP signals.                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ilcsr_u {
-       u64 ii_ilcsr_regval;
-       struct {
-               u64 i_nullto:6;
-               u64 i_rsvd_4:2;
-               u64 i_wrmrst:1;
-               u64 i_rsvd_3:1;
-               u64 i_llp_en:1;
-               u64 i_bm8:1;
-               u64 i_llp_stat:2;
-               u64 i_remote_power:1;
-               u64 i_rsvd_2:1;
-               u64 i_maxrtry:10;
-               u64 i_d_avail_sel:2;
-               u64 i_rsvd_1:4;
-               u64 i_maxbrst:10;
-               u64 i_rsvd:22;
-
-       } ii_ilcsr_fld_s;
-} ii_ilcsr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This is simply a status registers that monitors the LLP error       *
- * rate.                                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_illr_u {
-       u64 ii_illr_regval;
-       struct {
-               u64 i_sn_cnt:16;
-               u64 i_cb_cnt:16;
-               u64 i_rsvd:32;
-       } ii_illr_fld_s;
-} ii_illr_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  All II-detected non-BTE error interrupts are           *
- * specified via this register.                                         *
- * NOTE: The PI interrupt register address is hardcoded in the II. If   *
- * PI_ID==0, then the II sends an interrupt request (Duplonet PWRI      *
- * packet) to address offset 0x0180_0090 within the local register      *
- * address space of PI0 on the node specified by the NODE field. If     *
- * PI_ID==1, then the II sends the interrupt request to address         *
- * offset 0x01A0_0090 within the local register address space of PI1    *
- * on the node specified by the NODE field.                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iidsr_u {
-       u64 ii_iidsr_regval;
-       struct {
-               u64 i_level:8;
-               u64 i_pi_id:1;
-               u64 i_node:11;
-               u64 i_rsvd_3:4;
-               u64 i_enable:1;
-               u64 i_rsvd_2:3;
-               u64 i_int_sent:2;
-               u64 i_rsvd_1:2;
-               u64 i_pi0_forward_int:1;
-               u64 i_pi1_forward_int:1;
-               u64 i_rsvd:30;
-       } ii_iidsr_fld_s;
-} ii_iidsr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are two instances of this register. This register is used     *
- * for matching up the incoming responses from the graphics widget to   *
- * the processor that initiated the graphics operation. The             *
- * write-responses are converted to graphics credits and returned to    *
- * the processor so that the processor interface can manage the flow    *
- * control.                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_igfx0_u {
-       u64 ii_igfx0_regval;
-       struct {
-               u64 i_w_num:4;
-               u64 i_pi_id:1;
-               u64 i_n_num:12;
-               u64 i_p_num:1;
-               u64 i_rsvd:46;
-       } ii_igfx0_fld_s;
-} ii_igfx0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are two instances of this register. This register is used     *
- * for matching up the incoming responses from the graphics widget to   *
- * the processor that initiated the graphics operation. The             *
- * write-responses are converted to graphics credits and returned to    *
- * the processor so that the processor interface can manage the flow    *
- * control.                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_igfx1_u {
-       u64 ii_igfx1_regval;
-       struct {
-               u64 i_w_num:4;
-               u64 i_pi_id:1;
-               u64 i_n_num:12;
-               u64 i_p_num:1;
-               u64 i_rsvd:46;
-       } ii_igfx1_fld_s;
-} ii_igfx1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are two instances of this registers. These registers are      *
- * used as scratch registers for software use.                          *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iscr0_u {
-       u64 ii_iscr0_regval;
-       struct {
-               u64 i_scratch:64;
-       } ii_iscr0_fld_s;
-} ii_iscr0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are two instances of this registers. These registers are      *
- * used as scratch registers for software use.                          *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iscr1_u {
-       u64 ii_iscr1_regval;
-       struct {
-               u64 i_scratch:64;
-       } ii_iscr1_fld_s;
-} ii_iscr1_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a Shub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the SHub is thus the lower 16 GBytes per widget       * 
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the Shub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte1_u {
-       u64 ii_itte1_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte1_fld_s;
-} ii_itte1_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a Shub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the Shub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the Shub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte2_u {
-       u64 ii_itte2_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte2_fld_s;
-} ii_itte2_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a Shub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the Shub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the SHub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte3_u {
-       u64 ii_itte3_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte3_fld_s;
-} ii_itte3_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a SHub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the SHub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the SHub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte4_u {
-       u64 ii_itte4_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte4_fld_s;
-} ii_itte4_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a SHub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the Shub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the Shub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte5_u {
-       u64 ii_itte5_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte5_fld_s;
-} ii_itte5_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a Shub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the Shub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the Shub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte6_u {
-       u64 ii_itte6_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte6_fld_s;
-} ii_itte6_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are seven instances of translation table entry   *
- * registers. Each register maps a Shub Big Window to a 48-bit          *
- * address on Crosstalk.                                                *
- * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
- * number) are used to select one of these 7 registers. The Widget      *
- * number field is then derived from the W_NUM field for synthesizing   *
- * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
- * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
- * are padded with zeros. Although the maximum Crosstalk space          *
- * addressable by the Shub is thus the lower 16 GBytes per widget       *
- * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
- * space can be accessed.                                               *
- * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
- * Window number) are used to select one of these 7 registers. The      *
- * Widget number field is then derived from the W_NUM field for         *
- * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
- * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
- * field is used as Crosstalk[47], and remainder of the Crosstalk       *
- * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
- * Crosstalk space addressable by the SHub is thus the lower            *
- * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
- * of this space can be accessed.                                       *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_itte7_u {
-       u64 ii_itte7_regval;
-       struct {
-               u64 i_offset:5;
-               u64 i_rsvd_1:3;
-               u64 i_w_num:4;
-               u64 i_iosp:1;
-               u64 i_rsvd:51;
-       } ii_itte7_fld_s;
-} ii_itte7_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprb0_u {
-       u64 ii_iprb0_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprb0_fld_s;
-} ii_iprb0_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprb8_u {
-       u64 ii_iprb8_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprb8_fld_s;
-} ii_iprb8_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprb9_u {
-       u64 ii_iprb9_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprb9_fld_s;
-} ii_iprb9_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.        *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- *                                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprba_u {
-       u64 ii_iprba_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprba_fld_s;
-} ii_iprba_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprbb_u {
-       u64 ii_iprbb_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprbb_fld_s;
-} ii_iprbb_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprbc_u {
-       u64 ii_iprbc_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprbc_fld_s;
-} ii_iprbc_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprbd_u {
-       u64 ii_iprbd_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprbd_fld_s;
-} ii_iprbd_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of SHub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprbe_u {
-       u64 ii_iprbe_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprbe_fld_s;
-} ii_iprbe_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 9 instances of this register, one per        *
- * actual widget in this implementation of Shub and Crossbow.           *
- * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
- * refers to Crossbow's internal space.                                 *
- * This register contains the state elements per widget that are        *
- * necessary to manage the PIO flow control on Crosstalk and on the     *
- * Router Network. See the PIO Flow Control chapter for a complete      *
- * description of this register                                         *
- * The SPUR_WR bit requires some explanation. When this register is     *
- * written, the new value of the C field is captured in an internal     *
- * register so the hardware can remember what the programmer wrote      *
- * into the credit counter. The SPUR_WR bit sets whenever the C field   *
- * increments above this stored value, which indicates that there       *
- * have been more responses received than requests sent. The SPUR_WR    *
- * bit cannot be cleared until a value is written to the IPRBx          *
- * register; the write will correct the C field and capture its new     *
- * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
- * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
- * .                                                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprbf_u {
-       u64 ii_iprbf_regval;
-       struct {
-               u64 i_c:8;
-               u64 i_na:14;
-               u64 i_rsvd_2:2;
-               u64 i_nb:14;
-               u64 i_rsvd_1:2;
-               u64 i_m:2;
-               u64 i_f:1;
-               u64 i_of_cnt:5;
-               u64 i_error:1;
-               u64 i_rd_to:1;
-               u64 i_spur_wr:1;
-               u64 i_spur_rd:1;
-               u64 i_rsvd:11;
-               u64 i_mult_err:1;
-       } ii_iprbe_fld_s;
-} ii_iprbf_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register specifies the timeout value to use for monitoring     *
- * Crosstalk credits which are used outbound to Crosstalk. An           *
- * internal counter called the Crosstalk Credit Timeout Counter         *
- * increments every 128 II clocks. The counter starts counting          *
- * anytime the credit count drops below a threshold, and resets to      *
- * zero (stops counting) anytime the credit count is at or above the    *
- * threshold. The threshold is 1 credit in direct connect mode and 2    *
- * in Crossbow connect mode. When the internal Crosstalk Credit         *
- * Timeout Counter reaches the value programmed in this register, a     *
- * Crosstalk Credit Timeout has occurred. The internal counter is not   *
- * readable from software, and stops counting at its maximum value,     *
- * so it cannot cause more than one interrupt.                          *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ixcc_u {
-       u64 ii_ixcc_regval;
-       struct {
-               u64 i_time_out:26;
-               u64 i_rsvd:38;
-       } ii_ixcc_fld_s;
-} ii_ixcc_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register qualifies all the PIO and DMA            *
- * operations launched from widget 0 towards the SHub. In               *
- * addition, it also qualifies accesses by the BTE streams.             *
- * The bits in each field of this register are cleared by the SHub      *
- * upon detection of an error which requires widget 0 or the BTE        *
- * streams to be terminated. Whether or not widget x has access         *
- * rights to this SHub is determined by an AND of the device            *
- * enable bit in the appropriate field of this register and bit 0 in    *
- * the Wx_IAC field. The bits in this field are set by writing a 1 to   *
- * them. Incoming replies from Crosstalk are not subject to this        *
- * access control mechanism.                                            *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_imem_u {
-       u64 ii_imem_regval;
-       struct {
-               u64 i_w0_esd:1;
-               u64 i_rsvd_3:3;
-               u64 i_b0_esd:1;
-               u64 i_rsvd_2:3;
-               u64 i_b1_esd:1;
-               u64 i_rsvd_1:3;
-               u64 i_clr_precise:1;
-               u64 i_rsvd:51;
-       } ii_imem_fld_s;
-} ii_imem_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register specifies the timeout value to use for   *
- * monitoring Crosstalk tail flits coming into the Shub in the          *
- * TAIL_TO field. An internal counter associated with this register     *
- * is incremented every 128 II internal clocks (7 bits). The counter    *
- * starts counting anytime a header micropacket is received and stops   *
- * counting (and resets to zero) any time a micropacket with a Tail     *
- * bit is received. Once the counter reaches the threshold value        *
- * programmed in this register, it generates an interrupt to the        *
- * processor that is programmed into the IIDSR. The counter saturates   *
- * (does not roll over) at its maximum value, so it cannot cause        *
- * another interrupt until after it is cleared.                         *
- * The register also contains the Read Response Timeout values. The     *
- * Prescalar is 23 bits, and counts II clocks. An internal counter      *
- * increments on every II clock and when it reaches the value in the    *
- * Prescalar field, all IPRTE registers with their valid bits set       *
- * have their Read Response timers bumped. Whenever any of them match   *
- * the value in the RRSP_TO field, a Read Response Timeout has          *
- * occurred, and error handling occurs as described in the Error        *
- * Handling section of this document.                                   *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ixtt_u {
-       u64 ii_ixtt_regval;
-       struct {
-               u64 i_tail_to:26;
-               u64 i_rsvd_1:6;
-               u64 i_rrsp_ps:23;
-               u64 i_rrsp_to:5;
-               u64 i_rsvd:4;
-       } ii_ixtt_fld_s;
-} ii_ixtt_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Writing a 1 to the fields of this register clears the appropriate   *
- * error bits in other areas of SHub. Note that when the                *
- * E_PRB_x bits are used to clear error bits in PRB registers,          *
- * SPUR_RD and SPUR_WR may persist, because they require additional     *
- * action to clear them. See the IPRBx and IXSS Register                *
- * specifications.                                                      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ieclr_u {
-       u64 ii_ieclr_regval;
-       struct {
-               u64 i_e_prb_0:1;
-               u64 i_rsvd:7;
-               u64 i_e_prb_8:1;
-               u64 i_e_prb_9:1;
-               u64 i_e_prb_a:1;
-               u64 i_e_prb_b:1;
-               u64 i_e_prb_c:1;
-               u64 i_e_prb_d:1;
-               u64 i_e_prb_e:1;
-               u64 i_e_prb_f:1;
-               u64 i_e_crazy:1;
-               u64 i_e_bte_0:1;
-               u64 i_e_bte_1:1;
-               u64 i_reserved_1:10;
-               u64 i_spur_rd_hdr:1;
-               u64 i_cam_intr_to:1;
-               u64 i_cam_overflow:1;
-               u64 i_cam_read_miss:1;
-               u64 i_ioq_rep_underflow:1;
-               u64 i_ioq_req_underflow:1;
-               u64 i_ioq_rep_overflow:1;
-               u64 i_ioq_req_overflow:1;
-               u64 i_iiq_rep_overflow:1;
-               u64 i_iiq_req_overflow:1;
-               u64 i_ii_xn_rep_cred_overflow:1;
-               u64 i_ii_xn_req_cred_overflow:1;
-               u64 i_ii_xn_invalid_cmd:1;
-               u64 i_xn_ii_invalid_cmd:1;
-               u64 i_reserved_2:21;
-       } ii_ieclr_fld_s;
-} ii_ieclr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register controls both BTEs. SOFT_RESET is intended for        *
- * recovery after an error. COUNT controls the total number of CRBs     *
- * that both BTEs (combined) can use, which affects total BTE           *
- * bandwidth.                                                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibcr_u {
-       u64 ii_ibcr_regval;
-       struct {
-               u64 i_count:4;
-               u64 i_rsvd_1:4;
-               u64 i_soft_reset:1;
-               u64 i_rsvd:55;
-       } ii_ibcr_fld_s;
-} ii_ibcr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the header of a spurious read response       *
- * received from Crosstalk. A spurious read response is defined as a    *
- * read response received by II from a widget for which (1) the SIDN    *
- * has a value between 1 and 7, inclusive (II never sends requests to   *
- * these widgets (2) there is no valid IPRTE register which             *
- * corresponds to the TNUM, or (3) the widget indicated in SIDN is      *
- * not the same as the widget recorded in the IPRTE register            *
- * referenced by the TNUM. If this condition is true, and if the        *
- * IXSS[VALID] bit is clear, then the header of the spurious read       *
- * response is capture in IXSM and IXSS, and IXSS[VALID] is set. The    *
- * errant header is thereby captured, and no further spurious read      *
- * respones are captured until IXSS[VALID] is cleared by setting the    *
- * appropriate bit in IECLR. Every time a spurious read response is     *
- * detected, the SPUR_RD bit of the PRB corresponding to the incoming   *
- * message's SIDN field is set. This always happens, regardless of       *
- * whether a header is captured. The programmer should check            *
- * IXSM[SIDN] to determine which widget sent the spurious response,     *
- * because there may be more than one SPUR_RD bit set in the PRB        *
- * registers. The widget indicated by IXSM[SIDN] was the first          *
- * spurious read response to be received since the last time            *
- * IXSS[VALID] was clear. The SPUR_RD bit of the corresponding PRB      *
- * will be set. Any SPUR_RD bits in any other PRB registers indicate    *
- * spurious messages from other widets which were detected after the    *
- * header was captured..                                                *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ixsm_u {
-       u64 ii_ixsm_regval;
-       struct {
-               u64 i_byte_en:32;
-               u64 i_reserved:1;
-               u64 i_tag:3;
-               u64 i_alt_pactyp:4;
-               u64 i_bo:1;
-               u64 i_error:1;
-               u64 i_vbpm:1;
-               u64 i_gbr:1;
-               u64 i_ds:2;
-               u64 i_ct:1;
-               u64 i_tnum:5;
-               u64 i_pactyp:4;
-               u64 i_sidn:4;
-               u64 i_didn:4;
-       } ii_ixsm_fld_s;
-} ii_ixsm_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the sideband bits of a spurious read         *
- * response received from Crosstalk.                                    *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ixss_u {
-       u64 ii_ixss_regval;
-       struct {
-               u64 i_sideband:8;
-               u64 i_rsvd:55;
-               u64 i_valid:1;
-       } ii_ixss_fld_s;
-} ii_ixss_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register enables software to access the II LLP's test port.    *
- * Refer to the LLP 2.5 documentation for an explanation of the test    *
- * port. Software can write to this register to program the values      *
- * for the control fields (TestErrCapture, TestClear, TestFlit,         *
- * TestMask and TestSeed). Similarly, software can read from this       *
- * register to obtain the values of the test port's status outputs      *
- * (TestCBerr, TestValid and TestData).                                 *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ilct_u {
-       u64 ii_ilct_regval;
-       struct {
-               u64 i_test_seed:20;
-               u64 i_test_mask:8;
-               u64 i_test_data:20;
-               u64 i_test_valid:1;
-               u64 i_test_cberr:1;
-               u64 i_test_flit:3;
-               u64 i_test_clear:1;
-               u64 i_test_err_capture:1;
-               u64 i_rsvd:9;
-       } ii_ilct_fld_s;
-} ii_ilct_u_t;
-
-/************************************************************************
- *                                                                     *
- *  If the II detects an illegal incoming Duplonet packet (request or   *
- * reply) when VALID==0 in the IIEPH1 register, then it saves the       *
- * contents of the packet's header flit in the IIEPH1 and IIEPH2        *
- * registers, sets the VALID bit in IIEPH1, clears the OVERRUN bit,     *
- * and assigns a value to the ERR_TYPE field which indicates the        *
- * specific nature of the error. The II recognizes four different       *
- * types of errors: short request packets (ERR_TYPE==2), short reply    *
- * packets (ERR_TYPE==3), long request packets (ERR_TYPE==4) and long   *
- * reply packets (ERR_TYPE==5). The encodings for these types of        *
- * errors were chosen to be consistent with the same types of errors    *
- * indicated by the ERR_TYPE field in the LB_ERROR_HDR1 register (in    *
- * the LB unit). If the II detects an illegal incoming Duplonet         *
- * packet when VALID==1 in the IIEPH1 register, then it merely sets     *
- * the OVERRUN bit to indicate that a subsequent error has happened,    *
- * and does nothing further.                                            *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iieph1_u {
-       u64 ii_iieph1_regval;
-       struct {
-               u64 i_command:7;
-               u64 i_rsvd_5:1;
-               u64 i_suppl:14;
-               u64 i_rsvd_4:1;
-               u64 i_source:14;
-               u64 i_rsvd_3:1;
-               u64 i_err_type:4;
-               u64 i_rsvd_2:4;
-               u64 i_overrun:1;
-               u64 i_rsvd_1:3;
-               u64 i_valid:1;
-               u64 i_rsvd:13;
-       } ii_iieph1_fld_s;
-} ii_iieph1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register holds the Address field from the header flit of an    *
- * incoming erroneous Duplonet packet, along with the tail bit which    *
- * accompanied this header flit. This register is essentially an        *
- * extension of IIEPH1. Two registers were necessary because the 64     *
- * bits available in only a single register were insufficient to        *
- * capture the entire header flit of an erroneous packet.               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iieph2_u {
-       u64 ii_iieph2_regval;
-       struct {
-               u64 i_rsvd_0:3;
-               u64 i_address:47;
-               u64 i_rsvd_1:10;
-               u64 i_tail:1;
-               u64 i_rsvd:3;
-       } ii_iieph2_fld_s;
-} ii_iieph2_u_t;
-
-/******************************/
-
-/************************************************************************
- *                                                                     *
- *  This register's value is a bit vector that guards access from SXBs  *
- * to local registers within the II as well as to external Crosstalk    *
- * widgets                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_islapr_u {
-       u64 ii_islapr_regval;
-       struct {
-               u64 i_region:64;
-       } ii_islapr_fld_s;
-} ii_islapr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  A write to this register of the 56-bit value "Pup+Bun" will cause  *
- * the bit in the ISLAPR register corresponding to the region of the   *
- * requestor to be set (access allowed).                               (
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_islapo_u {
-       u64 ii_islapo_regval;
-       struct {
-               u64 i_io_sbx_ovrride:56;
-               u64 i_rsvd:8;
-       } ii_islapo_fld_s;
-} ii_islapo_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Determines how long the wrapper will wait aftr an interrupt is     *
- * initially issued from the II before it times out the outstanding    *
- * interrupt and drops it from the interrupt queue.                    * 
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iwi_u {
-       u64 ii_iwi_regval;
-       struct {
-               u64 i_prescale:24;
-               u64 i_rsvd:8;
-               u64 i_timeout:8;
-               u64 i_rsvd1:8;
-               u64 i_intrpt_retry_period:8;
-               u64 i_rsvd2:8;
-       } ii_iwi_fld_s;
-} ii_iwi_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Log errors which have occurred in the II wrapper. The errors are   *
- * cleared by writing to the IECLR register.                           * 
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iwel_u {
-       u64 ii_iwel_regval;
-       struct {
-               u64 i_intr_timed_out:1;
-               u64 i_rsvd:7;
-               u64 i_cam_overflow:1;
-               u64 i_cam_read_miss:1;
-               u64 i_rsvd1:2;
-               u64 i_ioq_rep_underflow:1;
-               u64 i_ioq_req_underflow:1;
-               u64 i_ioq_rep_overflow:1;
-               u64 i_ioq_req_overflow:1;
-               u64 i_iiq_rep_overflow:1;
-               u64 i_iiq_req_overflow:1;
-               u64 i_rsvd2:6;
-               u64 i_ii_xn_rep_cred_over_under:1;
-               u64 i_ii_xn_req_cred_over_under:1;
-               u64 i_rsvd3:6;
-               u64 i_ii_xn_invalid_cmd:1;
-               u64 i_xn_ii_invalid_cmd:1;
-               u64 i_rsvd4:30;
-       } ii_iwel_fld_s;
-} ii_iwel_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Controls the II wrapper.                                           * 
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iwc_u {
-       u64 ii_iwc_regval;
-       struct {
-               u64 i_dma_byte_swap:1;
-               u64 i_rsvd:3;
-               u64 i_cam_read_lines_reset:1;
-               u64 i_rsvd1:3;
-               u64 i_ii_xn_cred_over_under_log:1;
-               u64 i_rsvd2:19;
-               u64 i_xn_rep_iq_depth:5;
-               u64 i_rsvd3:3;
-               u64 i_xn_req_iq_depth:5;
-               u64 i_rsvd4:3;
-               u64 i_iiq_depth:6;
-               u64 i_rsvd5:12;
-               u64 i_force_rep_cred:1;
-               u64 i_force_req_cred:1;
-       } ii_iwc_fld_s;
-} ii_iwc_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Status in the II wrapper.                                          * 
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iws_u {
-       u64 ii_iws_regval;
-       struct {
-               u64 i_xn_rep_iq_credits:5;
-               u64 i_rsvd:3;
-               u64 i_xn_req_iq_credits:5;
-               u64 i_rsvd1:51;
-       } ii_iws_fld_s;
-} ii_iws_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Masks errors in the IWEL register.                                 *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iweim_u {
-       u64 ii_iweim_regval;
-       struct {
-               u64 i_intr_timed_out:1;
-               u64 i_rsvd:7;
-               u64 i_cam_overflow:1;
-               u64 i_cam_read_miss:1;
-               u64 i_rsvd1:2;
-               u64 i_ioq_rep_underflow:1;
-               u64 i_ioq_req_underflow:1;
-               u64 i_ioq_rep_overflow:1;
-               u64 i_ioq_req_overflow:1;
-               u64 i_iiq_rep_overflow:1;
-               u64 i_iiq_req_overflow:1;
-               u64 i_rsvd2:6;
-               u64 i_ii_xn_rep_cred_overflow:1;
-               u64 i_ii_xn_req_cred_overflow:1;
-               u64 i_rsvd3:6;
-               u64 i_ii_xn_invalid_cmd:1;
-               u64 i_xn_ii_invalid_cmd:1;
-               u64 i_rsvd4:30;
-       } ii_iweim_fld_s;
-} ii_iweim_u_t;
-
-/************************************************************************
- *                                                                     *
- *  A write to this register causes a particular field in the           *
- * corresponding widget's PRB entry to be adjusted up or down by 1.     *
- * This counter should be used when recovering from error and reset     *
- * conditions. Note that software would be capable of causing           *
- * inadvertent overflow or underflow of these counters.                 *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ipca_u {
-       u64 ii_ipca_regval;
-       struct {
-               u64 i_wid:4;
-               u64 i_adjust:1;
-               u64 i_rsvd_1:3;
-               u64 i_field:2;
-               u64 i_rsvd:54;
-       } ii_ipca_fld_s;
-} ii_ipca_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte0a_u {
-       u64 ii_iprte0a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte0a_fld_s;
-} ii_iprte0a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte1a_u {
-       u64 ii_iprte1a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte1a_fld_s;
-} ii_iprte1a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte2a_u {
-       u64 ii_iprte2a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte2a_fld_s;
-} ii_iprte2a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte3a_u {
-       u64 ii_iprte3a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte3a_fld_s;
-} ii_iprte3a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte4a_u {
-       u64 ii_iprte4a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte4a_fld_s;
-} ii_iprte4a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte5a_u {
-       u64 ii_iprte5a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte5a_fld_s;
-} ii_iprte5a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte6a_u {
-       u64 ii_iprte6a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprte6a_fld_s;
-} ii_iprte6a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte7a_u {
-       u64 ii_iprte7a_regval;
-       struct {
-               u64 i_rsvd_1:54;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } ii_iprtea7_fld_s;
-} ii_iprte7a_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte0b_u {
-       u64 ii_iprte0b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte0b_fld_s;
-} ii_iprte0b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte1b_u {
-       u64 ii_iprte1b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte1b_fld_s;
-} ii_iprte1b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte2b_u {
-       u64 ii_iprte2b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte2b_fld_s;
-} ii_iprte2b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte3b_u {
-       u64 ii_iprte3b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte3b_fld_s;
-} ii_iprte3b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte4b_u {
-       u64 ii_iprte4b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte4b_fld_s;
-} ii_iprte4b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte5b_u {
-       u64 ii_iprte5b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte5b_fld_s;
-} ii_iprte5b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte6b_u {
-       u64 ii_iprte6b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-
-       } ii_iprte6b_fld_s;
-} ii_iprte6b_u_t;
-
-/************************************************************************
- *                                                                     *
- *  There are 8 instances of this register. This register contains      *
- * the information that the II has to remember once it has launched a   *
- * PIO Read operation. The contents are used to form the correct        *
- * Router Network packet and direct the Crosstalk reply to the          *
- * appropriate processor.                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iprte7b_u {
-       u64 ii_iprte7b_regval;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_address:47;
-               u64 i_init:3;
-               u64 i_source:11;
-       } ii_iprte7b_fld_s;
-} ii_iprte7b_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  SHub II contains a feature which did not exist in      *
- * the Hub which automatically cleans up after a Read Response          *
- * timeout, including deallocation of the IPRTE and recovery of IBuf    *
- * space. The inclusion of this register in SHub is for backward        *
- * compatibility                                                        *
- * A write to this register causes an entry from the table of           *
- * outstanding PIO Read Requests to be freed and returned to the        *
- * stack of free entries. This register is used in handling the         *
- * timeout errors that result in a PIO Reply never returning from       *
- * Crosstalk.                                                           *
- * Note that this register does not affect the contents of the IPRTE    *
- * registers. The Valid bits in those registers have to be              *
- * specifically turned off by software.                                 *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ipdr_u {
-       u64 ii_ipdr_regval;
-       struct {
-               u64 i_te:3;
-               u64 i_rsvd_1:1;
-               u64 i_pnd:1;
-               u64 i_init_rpcnt:1;
-               u64 i_rsvd:58;
-       } ii_ipdr_fld_s;
-} ii_ipdr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  A write to this register causes a CRB entry to be returned to the   *
- * queue of free CRBs. The entry should have previously been cleared    *
- * (mark bit) via backdoor access to the pertinent CRB entry. This      *
- * register is used in the last step of handling the errors that are    *
- * captured and marked in CRB entries.  Briefly: 1) first error for     *
- * DMA write from a particular device, and first error for a            *
- * particular BTE stream, lead to a marked CRB entry, and processor     *
- * interrupt, 2) software reads the error information captured in the   *
- * CRB entry, and presumably takes some corrective action, 3)           *
- * software clears the mark bit, and finally 4) software writes to      *
- * the ICDR register to return the CRB entry to the list of free CRB    *
- * entries.                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icdr_u {
-       u64 ii_icdr_regval;
-       struct {
-               u64 i_crb_num:4;
-               u64 i_pnd:1;
-               u64 i_rsvd:59;
-       } ii_icdr_fld_s;
-} ii_icdr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register provides debug access to two FIFOs inside of II.      *
- * Both IOQ_MAX* fields of this register contain the instantaneous      *
- * depth (in units of the number of available entries) of the           *
- * associated IOQ FIFO.  A read of this register will return the        *
- * number of free entries on each FIFO at the time of the read.  So     *
- * when a FIFO is idle, the associated field contains the maximum       *
- * depth of the FIFO.  This register is writable for debug reasons      *
- * and is intended to be written with the maximum desired FIFO depth    *
- * while the FIFO is idle. Software must assure that II is idle when    *
- * this register is written. If there are any active entries in any     *
- * of these FIFOs when this register is written, the results are        *
- * undefined.                                                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ifdr_u {
-       u64 ii_ifdr_regval;
-       struct {
-               u64 i_ioq_max_rq:7;
-               u64 i_set_ioq_rq:1;
-               u64 i_ioq_max_rp:7;
-               u64 i_set_ioq_rp:1;
-               u64 i_rsvd:48;
-       } ii_ifdr_fld_s;
-} ii_ifdr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register allows the II to become sluggish in removing          *
- * messages from its inbound queue (IIQ). This will cause messages to   *
- * back up in either virtual channel. Disabling the "molasses" mode     *
- * subsequently allows the II to be tested under stress. In the         *
- * sluggish ("Molasses") mode, the localized effects of congestion      *
- * can be observed.                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iiap_u {
-       u64 ii_iiap_regval;
-       struct {
-               u64 i_rq_mls:6;
-               u64 i_rsvd_1:2;
-               u64 i_rp_mls:6;
-               u64 i_rsvd:50;
-       } ii_iiap_fld_s;
-} ii_iiap_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register allows several parameters of CRB operation to be      *
- * set. Note that writing to this register can have catastrophic side   *
- * effects, if the CRB is not quiescent, i.e. if the CRB is             *
- * processing protocol messages when the write occurs.                  *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icmr_u {
-       u64 ii_icmr_regval;
-       struct {
-               u64 i_sp_msg:1;
-               u64 i_rd_hdr:1;
-               u64 i_rsvd_4:2;
-               u64 i_c_cnt:4;
-               u64 i_rsvd_3:4;
-               u64 i_clr_rqpd:1;
-               u64 i_clr_rppd:1;
-               u64 i_rsvd_2:2;
-               u64 i_fc_cnt:4;
-               u64 i_crb_vld:15;
-               u64 i_crb_mark:15;
-               u64 i_rsvd_1:2;
-               u64 i_precise:1;
-               u64 i_rsvd:11;
-       } ii_icmr_fld_s;
-} ii_icmr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register allows control of the table portion of the CRB        *
- * logic via software. Control operations from this register have       *
- * priority over all incoming Crosstalk or BTE requests.                *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_iccr_u {
-       u64 ii_iccr_regval;
-       struct {
-               u64 i_crb_num:4;
-               u64 i_rsvd_1:4;
-               u64 i_cmd:8;
-               u64 i_pending:1;
-               u64 i_rsvd:47;
-       } ii_iccr_fld_s;
-} ii_iccr_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register allows the maximum timeout value to be programmed.    *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icto_u {
-       u64 ii_icto_regval;
-       struct {
-               u64 i_timeout:8;
-               u64 i_rsvd:56;
-       } ii_icto_fld_s;
-} ii_icto_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register allows the timeout prescalar to be programmed. An     *
- * internal counter is associated with this register. When the          *
- * internal counter reaches the value of the PRESCALE field, the        *
- * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT]   *
- * field). The internal counter resets to zero, and then continues      *
- * counting.                                                            *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ictp_u {
-       u64 ii_ictp_regval;
-       struct {
-               u64 i_prescale:24;
-               u64 i_rsvd:40;
-       } ii_ictp_fld_s;
-} ii_ictp_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
- * used for Crosstalk operations (both cacheline and partial            *
- * operations) or BTE/IO. Because the CRB entries are very wide, five   *
- * registers (_A to _E) are required to read and write each entry.      *
- * The CRB Entry registers can be conceptualized as rows and columns    *
- * (illustrated in the table above). Each row contains the 4            *
- * registers required for a single CRB Entry. The first doubleword      *
- * (column) for each entry is labeled A, and the second doubleword      *
- * (higher address) is labeled B, the third doubleword is labeled C,    *
- * the fourth doubleword is labeled D and the fifth doubleword is       *
- * labeled E. All CRB entries have their addresses on a quarter         *
- * cacheline aligned boundary.                   *
- * Upon reset, only the following fields are initialized: valid         *
- * (VLD), priority count, timeout, timeout valid, and context valid.    *
- * All other bits should be cleared by software before use (after       *
- * recovering any potential error state from before the reset).         *
- * The following four tables summarize the format for the four          *
- * registers that are used for each ICRB# Entry.                        *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icrb0_a_u {
-       u64 ii_icrb0_a_regval;
-       struct {
-               u64 ia_iow:1;
-               u64 ia_vld:1;
-               u64 ia_addr:47;
-               u64 ia_tnum:5;
-               u64 ia_sidn:4;
-               u64 ia_rsvd:6;
-       } ii_icrb0_a_fld_s;
-} ii_icrb0_a_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
- * used for Crosstalk operations (both cacheline and partial            *
- * operations) or BTE/IO. Because the CRB entries are very wide, five   *
- * registers (_A to _E) are required to read and write each entry.      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icrb0_b_u {
-       u64 ii_icrb0_b_regval;
-       struct {
-               u64 ib_xt_err:1;
-               u64 ib_mark:1;
-               u64 ib_ln_uce:1;
-               u64 ib_errcode:3;
-               u64 ib_error:1;
-               u64 ib_stall__bte_1:1;
-               u64 ib_stall__bte_0:1;
-               u64 ib_stall__intr:1;
-               u64 ib_stall_ib:1;
-               u64 ib_intvn:1;
-               u64 ib_wb:1;
-               u64 ib_hold:1;
-               u64 ib_ack:1;
-               u64 ib_resp:1;
-               u64 ib_ack_cnt:11;
-               u64 ib_rsvd:7;
-               u64 ib_exc:5;
-               u64 ib_init:3;
-               u64 ib_imsg:8;
-               u64 ib_imsgtype:2;
-               u64 ib_use_old:1;
-               u64 ib_rsvd_1:11;
-       } ii_icrb0_b_fld_s;
-} ii_icrb0_b_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
- * used for Crosstalk operations (both cacheline and partial            *
- * operations) or BTE/IO. Because the CRB entries are very wide, five   *
- * registers (_A to _E) are required to read and write each entry.      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icrb0_c_u {
-       u64 ii_icrb0_c_regval;
-       struct {
-               u64 ic_source:15;
-               u64 ic_size:2;
-               u64 ic_ct:1;
-               u64 ic_bte_num:1;
-               u64 ic_gbr:1;
-               u64 ic_resprqd:1;
-               u64 ic_bo:1;
-               u64 ic_suppl:15;
-               u64 ic_rsvd:27;
-       } ii_icrb0_c_fld_s;
-} ii_icrb0_c_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
- * used for Crosstalk operations (both cacheline and partial            *
- * operations) or BTE/IO. Because the CRB entries are very wide, five   *
- * registers (_A to _E) are required to read and write each entry.      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icrb0_d_u {
-       u64 ii_icrb0_d_regval;
-       struct {
-               u64 id_pa_be:43;
-               u64 id_bte_op:1;
-               u64 id_pr_psc:4;
-               u64 id_pr_cnt:4;
-               u64 id_sleep:1;
-               u64 id_rsvd:11;
-       } ii_icrb0_d_fld_s;
-} ii_icrb0_d_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
- * used for Crosstalk operations (both cacheline and partial            *
- * operations) or BTE/IO. Because the CRB entries are very wide, five   *
- * registers (_A to _E) are required to read and write each entry.      *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icrb0_e_u {
-       u64 ii_icrb0_e_regval;
-       struct {
-               u64 ie_timeout:8;
-               u64 ie_context:15;
-               u64 ie_rsvd:1;
-               u64 ie_tvld:1;
-               u64 ie_cvld:1;
-               u64 ie_rsvd_0:38;
-       } ii_icrb0_e_fld_s;
-} ii_icrb0_e_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the lower 64 bits of the header of the       *
- * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
- * register is set.                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icsml_u {
-       u64 ii_icsml_regval;
-       struct {
-               u64 i_tt_addr:47;
-               u64 i_newsuppl_ex:14;
-               u64 i_reserved:2;
-               u64 i_overflow:1;
-       } ii_icsml_fld_s;
-} ii_icsml_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the middle 64 bits of the header of the      *
- * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
- * register is set.                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icsmm_u {
-       u64 ii_icsmm_regval;
-       struct {
-               u64 i_tt_ack_cnt:11;
-               u64 i_reserved:53;
-       } ii_icsmm_fld_s;
-} ii_icsmm_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the microscopic state, all the inputs to     *
- * the protocol table, captured with the spurious message. Valid when   *
- * the SP_MSG bit in the ICMR register is set.                          *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_icsmh_u {
-       u64 ii_icsmh_regval;
-       struct {
-               u64 i_tt_vld:1;
-               u64 i_xerr:1;
-               u64 i_ft_cwact_o:1;
-               u64 i_ft_wact_o:1;
-               u64 i_ft_active_o:1;
-               u64 i_sync:1;
-               u64 i_mnusg:1;
-               u64 i_mnusz:1;
-               u64 i_plusz:1;
-               u64 i_plusg:1;
-               u64 i_tt_exc:5;
-               u64 i_tt_wb:1;
-               u64 i_tt_hold:1;
-               u64 i_tt_ack:1;
-               u64 i_tt_resp:1;
-               u64 i_tt_intvn:1;
-               u64 i_g_stall_bte1:1;
-               u64 i_g_stall_bte0:1;
-               u64 i_g_stall_il:1;
-               u64 i_g_stall_ib:1;
-               u64 i_tt_imsg:8;
-               u64 i_tt_imsgtype:2;
-               u64 i_tt_use_old:1;
-               u64 i_tt_respreqd:1;
-               u64 i_tt_bte_num:1;
-               u64 i_cbn:1;
-               u64 i_match:1;
-               u64 i_rpcnt_lt_34:1;
-               u64 i_rpcnt_ge_34:1;
-               u64 i_rpcnt_lt_18:1;
-               u64 i_rpcnt_ge_18:1;
-               u64 i_rpcnt_lt_2:1;
-               u64 i_rpcnt_ge_2:1;
-               u64 i_rqcnt_lt_18:1;
-               u64 i_rqcnt_ge_18:1;
-               u64 i_rqcnt_lt_2:1;
-               u64 i_rqcnt_ge_2:1;
-               u64 i_tt_device:7;
-               u64 i_tt_init:3;
-               u64 i_reserved:5;
-       } ii_icsmh_fld_s;
-} ii_icsmh_u_t;
-
-/************************************************************************
- *                                                                     *
- *  The Shub DEBUG unit provides a 3-bit selection signal to the        *
- * II core and a 3-bit selection signal to the fsbclk domain in the II  *
- * wrapper.                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_idbss_u {
-       u64 ii_idbss_regval;
-       struct {
-               u64 i_iioclk_core_submenu:3;
-               u64 i_rsvd:5;
-               u64 i_fsbclk_wrapper_submenu:3;
-               u64 i_rsvd_1:5;
-               u64 i_iioclk_menu:5;
-               u64 i_rsvd_2:43;
-       } ii_idbss_fld_s;
-} ii_idbss_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register is used to set up the length for a       *
- * transfer and then to monitor the progress of that transfer. This     *
- * register needs to be initialized before a transfer is started. A     *
- * legitimate write to this register will set the Busy bit, clear the   *
- * Error bit, and initialize the length to the value desired.           *
- * While the transfer is in progress, hardware will decrement the       *
- * length field with each successful block that is copied. Once the     *
- * transfer completes, hardware will clear the Busy bit. The length     *
- * field will also contain the number of cache lines left to be         *
- * transferred.                                                         *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibls0_u {
-       u64 ii_ibls0_regval;
-       struct {
-               u64 i_length:16;
-               u64 i_error:1;
-               u64 i_rsvd_1:3;
-               u64 i_busy:1;
-               u64 i_rsvd:43;
-       } ii_ibls0_fld_s;
-} ii_ibls0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register should be loaded before a transfer is started. The    *
- * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
- * address as described in Section 1.3, Figure2 and Figure3. Since      *
- * the bottom 7 bits of the address are always taken to be zero, BTE    *
- * transfers are always cacheline-aligned.                              *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibsa0_u {
-       u64 ii_ibsa0_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:42;
-               u64 i_rsvd:15;
-       } ii_ibsa0_fld_s;
-} ii_ibsa0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register should be loaded before a transfer is started. The    *
- * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
- * address as described in Section 1.3, Figure2 and Figure3. Since      *
- * the bottom 7 bits of the address are always taken to be zero, BTE    *
- * transfers are always cacheline-aligned.                              *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibda0_u {
-       u64 ii_ibda0_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:42;
-               u64 i_rsvd:15;
-       } ii_ibda0_fld_s;
-} ii_ibda0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Writing to this register sets up the attributes of the transfer     *
- * and initiates the transfer operation. Reading this register has      *
- * the side effect of terminating any transfer in progress. Note:       *
- * stopping a transfer midstream could have an adverse impact on the    *
- * other BTE. If a BTE stream has to be stopped (due to error           *
- * handling for example), both BTE streams should be stopped and        *
- * their transfers discarded.                                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibct0_u {
-       u64 ii_ibct0_regval;
-       struct {
-               u64 i_zerofill:1;
-               u64 i_rsvd_2:3;
-               u64 i_notify:1;
-               u64 i_rsvd_1:3;
-               u64 i_poison:1;
-               u64 i_rsvd:55;
-       } ii_ibct0_fld_s;
-} ii_ibct0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the address to which the WINV is sent.       *
- * This address has to be cache line aligned.                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibna0_u {
-       u64 ii_ibna0_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:42;
-               u64 i_rsvd:15;
-       } ii_ibna0_fld_s;
-} ii_ibna0_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the programmable level as well as the node   *
- * ID and PI unit of the processor to which the interrupt will be       *
- * sent.                                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibia0_u {
-       u64 ii_ibia0_regval;
-       struct {
-               u64 i_rsvd_2:1;
-               u64 i_node_id:11;
-               u64 i_rsvd_1:4;
-               u64 i_level:7;
-               u64 i_rsvd:41;
-       } ii_ibia0_fld_s;
-} ii_ibia0_u_t;
-
-/************************************************************************
- *                                                                     *
- * Description:  This register is used to set up the length for a       *
- * transfer and then to monitor the progress of that transfer. This     *
- * register needs to be initialized before a transfer is started. A     *
- * legitimate write to this register will set the Busy bit, clear the   *
- * Error bit, and initialize the length to the value desired.           *
- * While the transfer is in progress, hardware will decrement the       *
- * length field with each successful block that is copied. Once the     *
- * transfer completes, hardware will clear the Busy bit. The length     *
- * field will also contain the number of cache lines left to be         *
- * transferred.                                                         *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibls1_u {
-       u64 ii_ibls1_regval;
-       struct {
-               u64 i_length:16;
-               u64 i_error:1;
-               u64 i_rsvd_1:3;
-               u64 i_busy:1;
-               u64 i_rsvd:43;
-       } ii_ibls1_fld_s;
-} ii_ibls1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register should be loaded before a transfer is started. The    *
- * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
- * address as described in Section 1.3, Figure2 and Figure3. Since      *
- * the bottom 7 bits of the address are always taken to be zero, BTE    *
- * transfers are always cacheline-aligned.                              *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibsa1_u {
-       u64 ii_ibsa1_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:33;
-               u64 i_rsvd:24;
-       } ii_ibsa1_fld_s;
-} ii_ibsa1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register should be loaded before a transfer is started. The    *
- * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
- * address as described in Section 1.3, Figure2 and Figure3. Since      *
- * the bottom 7 bits of the address are always taken to be zero, BTE    *
- * transfers are always cacheline-aligned.                              *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibda1_u {
-       u64 ii_ibda1_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:33;
-               u64 i_rsvd:24;
-       } ii_ibda1_fld_s;
-} ii_ibda1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  Writing to this register sets up the attributes of the transfer     *
- * and initiates the transfer operation. Reading this register has      *
- * the side effect of terminating any transfer in progress. Note:       *
- * stopping a transfer midstream could have an adverse impact on the    *
- * other BTE. If a BTE stream has to be stopped (due to error           *
- * handling for example), both BTE streams should be stopped and        *
- * their transfers discarded.                                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibct1_u {
-       u64 ii_ibct1_regval;
-       struct {
-               u64 i_zerofill:1;
-               u64 i_rsvd_2:3;
-               u64 i_notify:1;
-               u64 i_rsvd_1:3;
-               u64 i_poison:1;
-               u64 i_rsvd:55;
-       } ii_ibct1_fld_s;
-} ii_ibct1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the address to which the WINV is sent.       *
- * This address has to be cache line aligned.                           *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibna1_u {
-       u64 ii_ibna1_regval;
-       struct {
-               u64 i_rsvd_1:7;
-               u64 i_addr:33;
-               u64 i_rsvd:24;
-       } ii_ibna1_fld_s;
-} ii_ibna1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register contains the programmable level as well as the node   *
- * ID and PI unit of the processor to which the interrupt will be       *
- * sent.                                                               *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ibia1_u {
-       u64 ii_ibia1_regval;
-       struct {
-               u64 i_pi_id:1;
-               u64 i_node_id:8;
-               u64 i_rsvd_1:7;
-               u64 i_level:7;
-               u64 i_rsvd:41;
-       } ii_ibia1_fld_s;
-} ii_ibia1_u_t;
-
-/************************************************************************
- *                                                                     *
- *  This register defines the resources that feed information into      *
- * the two performance counters located in the IO Performance           *
- * Profiling Register. There are 17 different quantities that can be    *
- * measured. Given these 17 different options, the two performance      *
- * counters have 15 of them in common; menu selections 0 through 0xE    *
- * are identical for each performance counter. As for the other two     *
- * options, one is available from one performance counter and the       *
- * other is available from the other performance counter. Hence, the    *
- * II supports all 17*16=272 possible combinations of quantities to     *
- * measure.                                                             *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ipcr_u {
-       u64 ii_ipcr_regval;
-       struct {
-               u64 i_ippr0_c:4;
-               u64 i_ippr1_c:4;
-               u64 i_icct:8;
-               u64 i_rsvd:48;
-       } ii_ipcr_fld_s;
-} ii_ipcr_u_t;
-
-/************************************************************************
- *                                                                     *
- *                                                                     *
- *                                                                     *
- ************************************************************************/
-
-typedef union ii_ippr_u {
-       u64 ii_ippr_regval;
-       struct {
-               u64 i_ippr0:32;
-               u64 i_ippr1:32;
-       } ii_ippr_fld_s;
-} ii_ippr_u_t;
-
-/************************************************************************
- *                                                                     *
- * The following defines which were not formed into structures are     *
- * probably identical to another register, and the name of the         *
- * register is provided against each of these registers. This          *
- * information needs to be checked carefully                           *
- *                                                                     *
- *             IIO_ICRB1_A             IIO_ICRB0_A                     *
- *             IIO_ICRB1_B             IIO_ICRB0_B                     *
- *             IIO_ICRB1_C             IIO_ICRB0_C                     *
- *             IIO_ICRB1_D             IIO_ICRB0_D                     *
- *             IIO_ICRB1_E             IIO_ICRB0_E                     *
- *             IIO_ICRB2_A             IIO_ICRB0_A                     *
- *             IIO_ICRB2_B             IIO_ICRB0_B                     *
- *             IIO_ICRB2_C             IIO_ICRB0_C                     *
- *             IIO_ICRB2_D             IIO_ICRB0_D                     *
- *             IIO_ICRB2_E             IIO_ICRB0_E                     *
- *             IIO_ICRB3_A             IIO_ICRB0_A                     *
- *             IIO_ICRB3_B             IIO_ICRB0_B                     *
- *             IIO_ICRB3_C             IIO_ICRB0_C                     *
- *             IIO_ICRB3_D             IIO_ICRB0_D                     *
- *             IIO_ICRB3_E             IIO_ICRB0_E                     *
- *             IIO_ICRB4_A             IIO_ICRB0_A                     *
- *             IIO_ICRB4_B             IIO_ICRB0_B                     *
- *             IIO_ICRB4_C             IIO_ICRB0_C                     *
- *             IIO_ICRB4_D             IIO_ICRB0_D                     *
- *             IIO_ICRB4_E             IIO_ICRB0_E                     *
- *             IIO_ICRB5_A             IIO_ICRB0_A                     *
- *             IIO_ICRB5_B             IIO_ICRB0_B                     *
- *             IIO_ICRB5_C             IIO_ICRB0_C                     *
- *             IIO_ICRB5_D             IIO_ICRB0_D                     *
- *             IIO_ICRB5_E             IIO_ICRB0_E                     *
- *             IIO_ICRB6_A             IIO_ICRB0_A                     *
- *             IIO_ICRB6_B             IIO_ICRB0_B                     *
- *             IIO_ICRB6_C             IIO_ICRB0_C                     *
- *             IIO_ICRB6_D             IIO_ICRB0_D                     *
- *             IIO_ICRB6_E             IIO_ICRB0_E                     *
- *             IIO_ICRB7_A             IIO_ICRB0_A                     *
- *             IIO_ICRB7_B             IIO_ICRB0_B                     *
- *             IIO_ICRB7_C             IIO_ICRB0_C                     *
- *             IIO_ICRB7_D             IIO_ICRB0_D                     *
- *             IIO_ICRB7_E             IIO_ICRB0_E                     *
- *             IIO_ICRB8_A             IIO_ICRB0_A                     *
- *             IIO_ICRB8_B             IIO_ICRB0_B                     *
- *             IIO_ICRB8_C             IIO_ICRB0_C                     *
- *             IIO_ICRB8_D             IIO_ICRB0_D                     *
- *             IIO_ICRB8_E             IIO_ICRB0_E                     *
- *             IIO_ICRB9_A             IIO_ICRB0_A                     *
- *             IIO_ICRB9_B             IIO_ICRB0_B                     *
- *             IIO_ICRB9_C             IIO_ICRB0_C                     *
- *             IIO_ICRB9_D             IIO_ICRB0_D                     *
- *             IIO_ICRB9_E             IIO_ICRB0_E                     *
- *             IIO_ICRBA_A             IIO_ICRB0_A                     *
- *             IIO_ICRBA_B             IIO_ICRB0_B                     *
- *             IIO_ICRBA_C             IIO_ICRB0_C                     *
- *             IIO_ICRBA_D             IIO_ICRB0_D                     *
- *             IIO_ICRBA_E             IIO_ICRB0_E                     *
- *             IIO_ICRBB_A             IIO_ICRB0_A                     *
- *             IIO_ICRBB_B             IIO_ICRB0_B                     *
- *             IIO_ICRBB_C             IIO_ICRB0_C                     *
- *             IIO_ICRBB_D             IIO_ICRB0_D                     *
- *             IIO_ICRBB_E             IIO_ICRB0_E                     *
- *             IIO_ICRBC_A             IIO_ICRB0_A                     *
- *             IIO_ICRBC_B             IIO_ICRB0_B                     *
- *             IIO_ICRBC_C             IIO_ICRB0_C                     *
- *             IIO_ICRBC_D             IIO_ICRB0_D                     *
- *             IIO_ICRBC_E             IIO_ICRB0_E                     *
- *             IIO_ICRBD_A             IIO_ICRB0_A                     *
- *             IIO_ICRBD_B             IIO_ICRB0_B                     *
- *             IIO_ICRBD_C             IIO_ICRB0_C                     *
- *             IIO_ICRBD_D             IIO_ICRB0_D                     *
- *             IIO_ICRBD_E             IIO_ICRB0_E                     *
- *             IIO_ICRBE_A             IIO_ICRB0_A                     *
- *             IIO_ICRBE_B             IIO_ICRB0_B                     *
- *             IIO_ICRBE_C             IIO_ICRB0_C                     *
- *             IIO_ICRBE_D             IIO_ICRB0_D                     *
- *             IIO_ICRBE_E             IIO_ICRB0_E                     *
- *                                                                     *
- ************************************************************************/
-
-/*
- * Slightly friendlier names for some common registers.
- */
-#define IIO_WIDGET              IIO_WID                /* Widget identification */
-#define IIO_WIDGET_STAT         IIO_WSTAT      /* Widget status register */
-#define IIO_WIDGET_CTRL         IIO_WCR                /* Widget control register */
-#define IIO_PROTECT             IIO_ILAPR      /* IO interface protection */
-#define IIO_PROTECT_OVRRD       IIO_ILAPO      /* IO protect override */
-#define IIO_OUTWIDGET_ACCESS    IIO_IOWA       /* Outbound widget access */
-#define IIO_INWIDGET_ACCESS     IIO_IIWA       /* Inbound widget access */
-#define IIO_INDEV_ERR_MASK      IIO_IIDEM      /* Inbound device error mask */
-#define IIO_LLP_CSR             IIO_ILCSR      /* LLP control and status */
-#define IIO_LLP_LOG             IIO_ILLR       /* LLP log */
-#define IIO_XTALKCC_TOUT        IIO_IXCC       /* Xtalk credit count timeout */
-#define IIO_XTALKTT_TOUT        IIO_IXTT       /* Xtalk tail timeout */
-#define IIO_IO_ERR_CLR          IIO_IECLR      /* IO error clear */
-#define IIO_IGFX_0             IIO_IGFX0
-#define IIO_IGFX_1             IIO_IGFX1
-#define IIO_IBCT_0             IIO_IBCT0
-#define IIO_IBCT_1             IIO_IBCT1
-#define IIO_IBLS_0             IIO_IBLS0
-#define IIO_IBLS_1             IIO_IBLS1
-#define IIO_IBSA_0             IIO_IBSA0
-#define IIO_IBSA_1             IIO_IBSA1
-#define IIO_IBDA_0             IIO_IBDA0
-#define IIO_IBDA_1             IIO_IBDA1
-#define IIO_IBNA_0             IIO_IBNA0
-#define IIO_IBNA_1             IIO_IBNA1
-#define IIO_IBIA_0             IIO_IBIA0
-#define IIO_IBIA_1             IIO_IBIA1
-#define IIO_IOPRB_0            IIO_IPRB0
-
-#define IIO_PRTE_A(_x)         (IIO_IPRTE0_A + (8 * (_x)))
-#define IIO_PRTE_B(_x)         (IIO_IPRTE0_B + (8 * (_x)))
-#define IIO_NUM_PRTES          8       /* Total number of PRB table entries */
-#define IIO_WIDPRTE_A(x)       IIO_PRTE_A(((x) - 8))   /* widget ID to its PRTE num */
-#define IIO_WIDPRTE_B(x)       IIO_PRTE_B(((x) - 8))   /* widget ID to its PRTE num */
-
-#define IIO_NUM_IPRBS          9
-
-#define IIO_LLP_CSR_IS_UP              0x00002000
-#define IIO_LLP_CSR_LLP_STAT_MASK       0x00003000
-#define IIO_LLP_CSR_LLP_STAT_SHFT       12
-
-#define IIO_LLP_CB_MAX  0xffff /* in ILLR CB_CNT, Max Check Bit errors */
-#define IIO_LLP_SN_MAX  0xffff /* in ILLR SN_CNT, Max Sequence Number errors */
-
-/* key to IIO_PROTECT_OVRRD */
-#define IIO_PROTECT_OVRRD_KEY   0x53474972756c6573ull  /* "SGIrules" */
-
-/* BTE register names */
-#define IIO_BTE_STAT_0          IIO_IBLS_0     /* Also BTE length/status 0 */
-#define IIO_BTE_SRC_0           IIO_IBSA_0     /* Also BTE source address  0 */
-#define IIO_BTE_DEST_0          IIO_IBDA_0     /* Also BTE dest. address 0 */
-#define IIO_BTE_CTRL_0          IIO_IBCT_0     /* Also BTE control/terminate 0 */
-#define IIO_BTE_NOTIFY_0        IIO_IBNA_0     /* Also BTE notification 0 */
-#define IIO_BTE_INT_0           IIO_IBIA_0     /* Also BTE interrupt 0 */
-#define IIO_BTE_OFF_0           0      /* Base offset from BTE 0 regs. */
-#define IIO_BTE_OFF_1          (IIO_IBLS_1 - IIO_IBLS_0)       /* Offset from base to BTE 1 */
-
-/* BTE register offsets from base */
-#define BTEOFF_STAT             0
-#define BTEOFF_SRC             (IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
-#define BTEOFF_DEST            (IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
-#define BTEOFF_CTRL            (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
-#define BTEOFF_NOTIFY          (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
-#define BTEOFF_INT             (IIO_BTE_INT_0 - IIO_BTE_STAT_0)
-
-/* names used in shub diags */
-#define IIO_BASE_BTE0   IIO_IBLS_0
-#define IIO_BASE_BTE1   IIO_IBLS_1
-
-/*
- * Macro which takes the widget number, and returns the
- * IO PRB address of that widget.
- * value _x is expected to be a widget number in the range
- * 0, 8 - 0xF
- */
-#define IIO_IOPRB(_x)  (IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \
-                       (_x) : \
-                       (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) )
-
-/* GFX Flow Control Node/Widget Register */
-#define IIO_IGFX_W_NUM_BITS    4       /* size of widget num field */
-#define IIO_IGFX_W_NUM_MASK    ((1<<IIO_IGFX_W_NUM_BITS)-1)
-#define IIO_IGFX_W_NUM_SHIFT   0
-#define IIO_IGFX_PI_NUM_BITS   1       /* size of PI num field */
-#define IIO_IGFX_PI_NUM_MASK   ((1<<IIO_IGFX_PI_NUM_BITS)-1)
-#define IIO_IGFX_PI_NUM_SHIFT  4
-#define IIO_IGFX_N_NUM_BITS    8       /* size of node num field */
-#define IIO_IGFX_N_NUM_MASK    ((1<<IIO_IGFX_N_NUM_BITS)-1)
-#define IIO_IGFX_N_NUM_SHIFT   5
-#define IIO_IGFX_P_NUM_BITS    1       /* size of processor num field */
-#define IIO_IGFX_P_NUM_MASK    ((1<<IIO_IGFX_P_NUM_BITS)-1)
-#define IIO_IGFX_P_NUM_SHIFT   16
-#define IIO_IGFX_INIT(widget, pi, node, cpu)                           (\
-       (((widget) & IIO_IGFX_W_NUM_MASK) << IIO_IGFX_W_NUM_SHIFT) |     \
-       (((pi)     & IIO_IGFX_PI_NUM_MASK)<< IIO_IGFX_PI_NUM_SHIFT)|     \
-       (((node)   & IIO_IGFX_N_NUM_MASK) << IIO_IGFX_N_NUM_SHIFT) |     \
-       (((cpu)    & IIO_IGFX_P_NUM_MASK) << IIO_IGFX_P_NUM_SHIFT))
-
-/* Scratch registers (all bits available) */
-#define IIO_SCRATCH_REG0        IIO_ISCR0
-#define IIO_SCRATCH_REG1        IIO_ISCR1
-#define IIO_SCRATCH_MASK        0xffffffffffffffffUL
-
-#define IIO_SCRATCH_BIT0_0      0x0000000000000001UL
-#define IIO_SCRATCH_BIT0_1      0x0000000000000002UL
-#define IIO_SCRATCH_BIT0_2      0x0000000000000004UL
-#define IIO_SCRATCH_BIT0_3      0x0000000000000008UL
-#define IIO_SCRATCH_BIT0_4      0x0000000000000010UL
-#define IIO_SCRATCH_BIT0_5      0x0000000000000020UL
-#define IIO_SCRATCH_BIT0_6      0x0000000000000040UL
-#define IIO_SCRATCH_BIT0_7      0x0000000000000080UL
-#define IIO_SCRATCH_BIT0_8      0x0000000000000100UL
-#define IIO_SCRATCH_BIT0_9      0x0000000000000200UL
-#define IIO_SCRATCH_BIT0_A      0x0000000000000400UL
-
-#define IIO_SCRATCH_BIT1_0      0x0000000000000001UL
-#define IIO_SCRATCH_BIT1_1      0x0000000000000002UL
-/* IO Translation Table Entries */
-#define IIO_NUM_ITTES   7      /* ITTEs numbered 0..6 */
-                                       /* Hw manuals number them 1..7! */
-/*
- * IIO_IMEM Register fields.
- */
-#define IIO_IMEM_W0ESD  0x1UL  /* Widget 0 shut down due to error */
-#define IIO_IMEM_B0ESD (1UL << 4)      /* BTE 0 shut down due to error */
-#define IIO_IMEM_B1ESD (1UL << 8)      /* BTE 1 Shut down due to error */
-
-/*
- * As a permanent workaround for a bug in the PI side of the shub, we've
- * redefined big window 7 as small window 0.
- XXX does this still apply for SN1??
- */
-#define HUB_NUM_BIG_WINDOW     (IIO_NUM_ITTES - 1)
-
-/*
- * Use the top big window as a surrogate for the first small window
- */
-#define SWIN0_BIGWIN            HUB_NUM_BIG_WINDOW
-
-#define ILCSR_WARM_RESET        0x100
-
-/*
- * CRB manipulation macros
- *     The CRB macros are slightly complicated, since there are up to
- *     four registers associated with each CRB entry.
- */
-#define IIO_NUM_CRBS            15     /* Number of CRBs */
-#define IIO_NUM_PC_CRBS         4      /* Number of partial cache CRBs */
-#define IIO_ICRB_OFFSET         8
-#define IIO_ICRB_0              IIO_ICRB0_A
-#define IIO_ICRB_ADDR_SHFT     2       /* Shift to get proper address */
-/* XXX - This is now tuneable:
-        #define IIO_FIRST_PC_ENTRY 12
- */
-
-#define IIO_ICRB_A(_x) ((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))))
-#define IIO_ICRB_B(_x) ((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET))
-#define IIO_ICRB_C(_x) ((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET))
-#define IIO_ICRB_D(_x) ((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET))
-#define IIO_ICRB_E(_x) ((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET))
-
-#define TNUM_TO_WIDGET_DEV(_tnum)      (_tnum & 0x7)
-
-/*
- * values for "ecode" field
- */
-#define IIO_ICRB_ECODE_DERR     0      /* Directory error due to IIO access */
-#define IIO_ICRB_ECODE_PERR     1      /* Poison error on IO access */
-#define IIO_ICRB_ECODE_WERR     2      /* Write error by IIO access
-                                        * e.g. WINV to a Read only line. */
-#define IIO_ICRB_ECODE_AERR     3      /* Access error caused by IIO access */
-#define IIO_ICRB_ECODE_PWERR    4      /* Error on partial write */
-#define IIO_ICRB_ECODE_PRERR    5      /* Error on partial read  */
-#define IIO_ICRB_ECODE_TOUT     6      /* CRB timeout before deallocating */
-#define IIO_ICRB_ECODE_XTERR    7      /* Incoming xtalk pkt had error bit */
-
-/*
- * Values for field imsgtype
- */
-#define IIO_ICRB_IMSGT_XTALK    0      /* Incoming message from Xtalk */
-#define IIO_ICRB_IMSGT_BTE      1      /* Incoming message from BTE    */
-#define IIO_ICRB_IMSGT_SN1NET   2      /* Incoming message from SN1 net */
-#define IIO_ICRB_IMSGT_CRB      3      /* Incoming message from CRB ???  */
-
-/*
- * values for field initiator.
- */
-#define IIO_ICRB_INIT_XTALK     0      /* Message originated in xtalk  */
-#define IIO_ICRB_INIT_BTE0      0x1    /* Message originated in BTE 0  */
-#define IIO_ICRB_INIT_SN1NET    0x2    /* Message originated in SN1net */
-#define IIO_ICRB_INIT_CRB       0x3    /* Message originated in CRB ?  */
-#define IIO_ICRB_INIT_BTE1      0x5    /* MEssage originated in BTE 1  */
-
-/*
- * Number of credits Hub widget has while sending req/response to
- * xbow.
- * Value of 3 is required by Xbow 1.1
- * We may be able to increase this to 4 with Xbow 1.2.
- */
-#define                   HUBII_XBOW_CREDIT       3
-#define                   HUBII_XBOW_REV2_CREDIT  4
-
-/*
- * Number of credits that xtalk devices should use when communicating
- * with a SHub (depth of SHub's queue).
- */
-#define HUB_CREDIT 4
-
-/*
- * Some IIO_PRB fields
- */
-#define IIO_PRB_MULTI_ERR      (1LL << 63)
-#define IIO_PRB_SPUR_RD                (1LL << 51)
-#define IIO_PRB_SPUR_WR                (1LL << 50)
-#define IIO_PRB_RD_TO          (1LL << 49)
-#define IIO_PRB_ERROR          (1LL << 48)
-
-/*************************************************************************
-
- Some of the IIO field masks and shifts are defined here.
- This is in order to maintain compatibility in SN0 and SN1 code
-**************************************************************************/
-
-/*
- * ICMR register fields
- * (Note: the IIO_ICMR_P_CNT and IIO_ICMR_PC_VLD from Hub are not
- * present in SHub)
- */
-
-#define IIO_ICMR_CRB_VLD_SHFT   20
-#define IIO_ICMR_CRB_VLD_MASK  (0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
-
-#define IIO_ICMR_FC_CNT_SHFT    16
-#define IIO_ICMR_FC_CNT_MASK   (0xf << IIO_ICMR_FC_CNT_SHFT)
-
-#define IIO_ICMR_C_CNT_SHFT     4
-#define IIO_ICMR_C_CNT_MASK    (0xf << IIO_ICMR_C_CNT_SHFT)
-
-#define IIO_ICMR_PRECISE       (1UL << 52)
-#define IIO_ICMR_CLR_RPPD      (1UL << 13)
-#define IIO_ICMR_CLR_RQPD      (1UL << 12)
-
-/*
- * IIO PIO Deallocation register field masks : (IIO_IPDR)
- XXX present but not needed in bedrock?  See the manual.
- */
-#define IIO_IPDR_PND           (1 << 4)
-
-/*
- * IIO CRB deallocation register field masks: (IIO_ICDR)
- */
-#define IIO_ICDR_PND           (1 << 4)
-
-/* 
- * IO BTE Length/Status (IIO_IBLS) register bit field definitions
- */
-#define IBLS_BUSY              (0x1UL << 20)
-#define IBLS_ERROR_SHFT                16
-#define IBLS_ERROR             (0x1UL << IBLS_ERROR_SHFT)
-#define IBLS_LENGTH_MASK       0xffff
-
-/*
- * IO BTE Control/Terminate register (IBCT) register bit field definitions
- */
-#define IBCT_POISON            (0x1UL << 8)
-#define IBCT_NOTIFY            (0x1UL << 4)
-#define IBCT_ZFIL_MODE         (0x1UL << 0)
-
-/*
- * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2)
- */
-#define IIEPH1_VALID           (1UL << 44)
-#define IIEPH1_OVERRUN         (1UL << 40)
-#define IIEPH1_ERR_TYPE_SHFT   32
-#define IIEPH1_ERR_TYPE_MASK   0xf
-#define IIEPH1_SOURCE_SHFT     20
-#define IIEPH1_SOURCE_MASK     11
-#define IIEPH1_SUPPL_SHFT      8
-#define IIEPH1_SUPPL_MASK      11
-#define IIEPH1_CMD_SHFT                0
-#define IIEPH1_CMD_MASK                7
-
-#define IIEPH2_TAIL            (1UL << 40)
-#define IIEPH2_ADDRESS_SHFT    0
-#define IIEPH2_ADDRESS_MASK    38
-
-#define IIEPH1_ERR_SHORT_REQ   2
-#define IIEPH1_ERR_SHORT_REPLY 3
-#define IIEPH1_ERR_LONG_REQ    4
-#define IIEPH1_ERR_LONG_REPLY  5
-
-/*
- * IO Error Clear register bit field definitions
- */
-#define IECLR_PI1_FWD_INT      (1UL << 31)     /* clear PI1_FORWARD_INT in iidsr */
-#define IECLR_PI0_FWD_INT      (1UL << 30)     /* clear PI0_FORWARD_INT in iidsr */
-#define IECLR_SPUR_RD_HDR      (1UL << 29)     /* clear valid bit in ixss reg */
-#define IECLR_BTE1             (1UL << 18)     /* clear bte error 1 */
-#define IECLR_BTE0             (1UL << 17)     /* clear bte error 0 */
-#define IECLR_CRAZY            (1UL << 16)     /* clear crazy bit in wstat reg */
-#define IECLR_PRB_F            (1UL << 15)     /* clear err bit in PRB_F reg */
-#define IECLR_PRB_E            (1UL << 14)     /* clear err bit in PRB_E reg */
-#define IECLR_PRB_D            (1UL << 13)     /* clear err bit in PRB_D reg */
-#define IECLR_PRB_C            (1UL << 12)     /* clear err bit in PRB_C reg */
-#define IECLR_PRB_B            (1UL << 11)     /* clear err bit in PRB_B reg */
-#define IECLR_PRB_A            (1UL << 10)     /* clear err bit in PRB_A reg */
-#define IECLR_PRB_9            (1UL << 9)      /* clear err bit in PRB_9 reg */
-#define IECLR_PRB_8            (1UL << 8)      /* clear err bit in PRB_8 reg */
-#define IECLR_PRB_0            (1UL << 0)      /* clear err bit in PRB_0 reg */
-
-/*
- * IIO CRB control register Fields: IIO_ICCR 
- */
-#define        IIO_ICCR_PENDING        0x10000
-#define        IIO_ICCR_CMD_MASK       0xFF
-#define        IIO_ICCR_CMD_SHFT       7
-#define        IIO_ICCR_CMD_NOP        0x0     /* No Op */
-#define        IIO_ICCR_CMD_WAKE       0x100   /* Reactivate CRB entry and process */
-#define        IIO_ICCR_CMD_TIMEOUT    0x200   /* Make CRB timeout & mark invalid */
-#define        IIO_ICCR_CMD_EJECT      0x400   /* Contents of entry written to memory
-                                        * via a WB
-                                        */
-#define        IIO_ICCR_CMD_FLUSH      0x800
-
-/*
- *
- * CRB Register description.
- *
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
- *
- * Many of the fields in CRB are status bits used by hardware
- * for implementation of the protocol. It's very dangerous to
- * mess around with the CRB registers.
- *
- * It's OK to read the CRB registers and try to make sense out of the
- * fields in CRB.
- *
- * Updating CRB requires all activities in Hub IIO to be quiesced.
- * otherwise, a write to CRB could corrupt other CRB entries.
- * CRBs are here only as a back door peek to shub IIO's status.
- * Quiescing implies  no dmas no PIOs
- * either directly from the cpu or from sn0net.
- * this is not something that can be done easily. So, AVOID updating
- * CRBs.
- */
-
-/*
- * Easy access macros for CRBs, all 5 registers (A-E)
- */
-typedef ii_icrb0_a_u_t icrba_t;
-#define a_sidn         ii_icrb0_a_fld_s.ia_sidn
-#define a_tnum         ii_icrb0_a_fld_s.ia_tnum
-#define a_addr          ii_icrb0_a_fld_s.ia_addr
-#define a_valid         ii_icrb0_a_fld_s.ia_vld
-#define a_iow           ii_icrb0_a_fld_s.ia_iow
-#define a_regvalue     ii_icrb0_a_regval
-
-typedef ii_icrb0_b_u_t icrbb_t;
-#define b_use_old       ii_icrb0_b_fld_s.ib_use_old
-#define b_imsgtype      ii_icrb0_b_fld_s.ib_imsgtype
-#define b_imsg          ii_icrb0_b_fld_s.ib_imsg
-#define b_initiator     ii_icrb0_b_fld_s.ib_init
-#define b_exc           ii_icrb0_b_fld_s.ib_exc
-#define b_ackcnt        ii_icrb0_b_fld_s.ib_ack_cnt
-#define b_resp          ii_icrb0_b_fld_s.ib_resp
-#define b_ack           ii_icrb0_b_fld_s.ib_ack
-#define b_hold          ii_icrb0_b_fld_s.ib_hold
-#define b_wb            ii_icrb0_b_fld_s.ib_wb
-#define b_intvn         ii_icrb0_b_fld_s.ib_intvn
-#define b_stall_ib      ii_icrb0_b_fld_s.ib_stall_ib
-#define b_stall_int     ii_icrb0_b_fld_s.ib_stall__intr
-#define b_stall_bte_0   ii_icrb0_b_fld_s.ib_stall__bte_0
-#define b_stall_bte_1   ii_icrb0_b_fld_s.ib_stall__bte_1
-#define b_error         ii_icrb0_b_fld_s.ib_error
-#define b_ecode         ii_icrb0_b_fld_s.ib_errcode
-#define b_lnetuce       ii_icrb0_b_fld_s.ib_ln_uce
-#define b_mark          ii_icrb0_b_fld_s.ib_mark
-#define b_xerr          ii_icrb0_b_fld_s.ib_xt_err
-#define b_regvalue     ii_icrb0_b_regval
-
-typedef ii_icrb0_c_u_t icrbc_t;
-#define c_suppl         ii_icrb0_c_fld_s.ic_suppl
-#define c_barrop        ii_icrb0_c_fld_s.ic_bo
-#define c_doresp        ii_icrb0_c_fld_s.ic_resprqd
-#define c_gbr           ii_icrb0_c_fld_s.ic_gbr
-#define c_btenum        ii_icrb0_c_fld_s.ic_bte_num
-#define c_cohtrans      ii_icrb0_c_fld_s.ic_ct
-#define c_xtsize        ii_icrb0_c_fld_s.ic_size
-#define c_source        ii_icrb0_c_fld_s.ic_source
-#define c_regvalue     ii_icrb0_c_regval
-
-typedef ii_icrb0_d_u_t icrbd_t;
-#define d_sleep         ii_icrb0_d_fld_s.id_sleep
-#define d_pricnt        ii_icrb0_d_fld_s.id_pr_cnt
-#define d_pripsc        ii_icrb0_d_fld_s.id_pr_psc
-#define d_bteop         ii_icrb0_d_fld_s.id_bte_op
-#define d_bteaddr       ii_icrb0_d_fld_s.id_pa_be      /* ic_pa_be fld has 2 names */
-#define d_benable       ii_icrb0_d_fld_s.id_pa_be      /* ic_pa_be fld has 2 names */
-#define d_regvalue     ii_icrb0_d_regval
-
-typedef ii_icrb0_e_u_t icrbe_t;
-#define icrbe_ctxtvld   ii_icrb0_e_fld_s.ie_cvld
-#define icrbe_toutvld   ii_icrb0_e_fld_s.ie_tvld
-#define icrbe_context   ii_icrb0_e_fld_s.ie_context
-#define icrbe_timeout   ii_icrb0_e_fld_s.ie_timeout
-#define e_regvalue     ii_icrb0_e_regval
-
-/* Number of widgets supported by shub */
-#define HUB_NUM_WIDGET          9
-#define HUB_WIDGET_ID_MIN       0x8
-#define HUB_WIDGET_ID_MAX       0xf
-
-#define HUB_WIDGET_PART_NUM     0xc120
-#define MAX_HUBS_PER_XBOW       2
-
-/* A few more #defines for backwards compatibility */
-#define iprb_t          ii_iprb0_u_t
-#define iprb_regval     ii_iprb0_regval
-#define iprb_mult_err  ii_iprb0_fld_s.i_mult_err
-#define iprb_spur_rd   ii_iprb0_fld_s.i_spur_rd
-#define iprb_spur_wr   ii_iprb0_fld_s.i_spur_wr
-#define iprb_rd_to     ii_iprb0_fld_s.i_rd_to
-#define iprb_ovflow     ii_iprb0_fld_s.i_of_cnt
-#define iprb_error      ii_iprb0_fld_s.i_error
-#define iprb_ff         ii_iprb0_fld_s.i_f
-#define iprb_mode       ii_iprb0_fld_s.i_m
-#define iprb_bnakctr    ii_iprb0_fld_s.i_nb
-#define iprb_anakctr    ii_iprb0_fld_s.i_na
-#define iprb_xtalkctr   ii_iprb0_fld_s.i_c
-
-#define LNK_STAT_WORKING        0x2            /* LLP is working */
-
-#define IIO_WSTAT_ECRAZY       (1ULL << 32)    /* Hub gone crazy */
-#define IIO_WSTAT_TXRETRY      (1ULL << 9)     /* Hub Tx Retry timeout */
-#define IIO_WSTAT_TXRETRY_MASK  0x7F           /* should be 0xFF?? */
-#define IIO_WSTAT_TXRETRY_SHFT  16
-#define IIO_WSTAT_TXRETRY_CNT(w)       (((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
-                                       IIO_WSTAT_TXRETRY_MASK)
-
-/* Number of II perf. counters we can multiplex at once */
-
-#define IO_PERF_SETS   32
-
-/* Bit for the widget in inbound access register */
-#define IIO_IIWA_WIDGET(_w)    ((u64)(1ULL << _w))
-/* Bit for the widget in outbound access register */
-#define IIO_IOWA_WIDGET(_w)    ((u64)(1ULL << _w))
-
-/* NOTE: The following define assumes that we are going to get
- * widget numbers from 8 thru F and the device numbers within
- * widget from 0 thru 7.
- */
-#define IIO_IIDEM_WIDGETDEV_MASK(w, d) ((u64)(1ULL << (8 * ((w) - 8) + (d))))
-
-/* IO Interrupt Destination Register */
-#define IIO_IIDSR_SENT_SHIFT    28
-#define IIO_IIDSR_SENT_MASK     0x30000000
-#define IIO_IIDSR_ENB_SHIFT     24
-#define IIO_IIDSR_ENB_MASK      0x01000000
-#define IIO_IIDSR_NODE_SHIFT    9
-#define IIO_IIDSR_NODE_MASK     0x000ff700
-#define IIO_IIDSR_PI_ID_SHIFT   8
-#define IIO_IIDSR_PI_ID_MASK    0x00000100
-#define IIO_IIDSR_LVL_SHIFT     0
-#define IIO_IIDSR_LVL_MASK      0x000000ff
-
-/* Xtalk timeout threshold register (IIO_IXTT) */
-#define IXTT_RRSP_TO_SHFT      55      /* read response timeout */
-#define IXTT_RRSP_TO_MASK      (0x1FULL << IXTT_RRSP_TO_SHFT)
-#define IXTT_RRSP_PS_SHFT      32      /* read responsed TO prescalar */
-#define IXTT_RRSP_PS_MASK      (0x7FFFFFULL << IXTT_RRSP_PS_SHFT)
-#define IXTT_TAIL_TO_SHFT      0       /* tail timeout counter threshold */
-#define IXTT_TAIL_TO_MASK      (0x3FFFFFFULL << IXTT_TAIL_TO_SHFT)
-
-/*
- * The IO LLP control status register and widget control register
- */
-
-typedef union hubii_wcr_u {
-       u64 wcr_reg_value;
-       struct {
-               u64 wcr_widget_id:4,    /* LLP crossbar credit */
-                wcr_tag_mode:1,        /* Tag mode */
-                wcr_rsvd1:8,   /* Reserved */
-                wcr_xbar_crd:3,        /* LLP crossbar credit */
-                wcr_f_bad_pkt:1,       /* Force bad llp pkt enable */
-                wcr_dir_con:1, /* widget direct connect */
-                wcr_e_thresh:5,        /* elasticity threshold */
-                wcr_rsvd:41;   /* unused */
-       } wcr_fields_s;
-} hubii_wcr_t;
-
-#define iwcr_dir_con    wcr_fields_s.wcr_dir_con
-
-/* The structures below are defined to extract and modify the ii
-performance registers */
-
-/* io_perf_sel allows the caller to specify what tests will be
-   performed */
-
-typedef union io_perf_sel {
-       u64 perf_sel_reg;
-       struct {
-               u64 perf_ippr0:4, perf_ippr1:4, perf_icct:8, perf_rsvd:48;
-       } perf_sel_bits;
-} io_perf_sel_t;
-
-/* io_perf_cnt is to extract the count from the shub registers. Due to
-   hardware problems there is only one counter, not two. */
-
-typedef union io_perf_cnt {
-       u64 perf_cnt;
-       struct {
-               u64 perf_cnt:20, perf_rsvd2:12, perf_rsvd1:32;
-       } perf_cnt_bits;
-
-} io_perf_cnt_t;
-
-typedef union iprte_a {
-       u64 entry;
-       struct {
-               u64 i_rsvd_1:3;
-               u64 i_addr:38;
-               u64 i_init:3;
-               u64 i_source:8;
-               u64 i_rsvd:2;
-               u64 i_widget:4;
-               u64 i_to_cnt:5;
-               u64 i_vld:1;
-       } iprte_fields;
-} iprte_a_t;
-
-#endif                         /* _ASM_IA64_SN_SHUBIO_H */
diff --git a/arch/ia64/include/asm/sn/simulator.h b/arch/ia64/include/asm/sn/simulator.h
deleted file mode 100644 (file)
index c2611f6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_SIMULATOR_H
-#define _ASM_IA64_SN_SIMULATOR_H
-
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_SGI_UV)
-#define SNMAGIC 0xaeeeeeee8badbeefL
-#define IS_MEDUSA()                    ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;})
-
-#define SIMULATOR_SLEEP()              asm("nop.i 0x8beef")
-#define IS_RUNNING_ON_SIMULATOR()      (sn_prom_type)
-#define IS_RUNNING_ON_FAKE_PROM()      (sn_prom_type == 2)
-extern int sn_prom_type;               /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
-#else
-#define IS_MEDUSA()                    0
-#define SIMULATOR_SLEEP()
-#define IS_RUNNING_ON_SIMULATOR()      0
-#endif
-
-#endif /* _ASM_IA64_SN_SIMULATOR_H */
diff --git a/arch/ia64/include/asm/sn/sn2/sn_hwperf.h b/arch/ia64/include/asm/sn/sn2/sn_hwperf.h
deleted file mode 100644 (file)
index e61ebac..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
- *
- * Data types used by the SN_SAL_HWPERF_OP SAL call for monitoring
- * SGI Altix node and router hardware
- *
- * Mark Goodwin <markgw@sgi.com> Mon Aug 30 12:23:46 EST 2004
- */
-
-#ifndef SN_HWPERF_H
-#define SN_HWPERF_H
-
-/*
- * object structure. SN_HWPERF_ENUM_OBJECTS and SN_HWPERF_GET_CPU_INFO
- * return an array of these. Do not change this without also
- * changing the corresponding SAL code.
- */
-#define SN_HWPERF_MAXSTRING            128
-struct sn_hwperf_object_info {
-       u32 id;
-       union {
-               struct {
-                       u64 this_part:1;
-                       u64 is_shared:1;
-               } fields;
-               struct {
-                       u64 flags;
-                       u64 reserved;
-               } b;
-       } f;
-       char name[SN_HWPERF_MAXSTRING];
-       char location[SN_HWPERF_MAXSTRING];
-       u32 ports;
-};
-
-#define sn_hwp_this_part       f.fields.this_part
-#define sn_hwp_is_shared       f.fields.is_shared
-#define sn_hwp_flags           f.b.flags
-
-/* macros for object classification */
-#define SN_HWPERF_IS_NODE(x)           ((x) && strstr((x)->name, "SHub"))
-#define SN_HWPERF_IS_NODE_SHUB2(x)     ((x) && strstr((x)->name, "SHub 2."))
-#define SN_HWPERF_IS_IONODE(x)         ((x) && strstr((x)->name, "TIO"))
-#define SN_HWPERF_IS_NL3ROUTER(x)      ((x) && strstr((x)->name, "NL3Router"))
-#define SN_HWPERF_IS_NL4ROUTER(x)      ((x) && strstr((x)->name, "NL4Router"))
-#define SN_HWPERF_IS_OLDROUTER(x)      ((x) && strstr((x)->name, "Router"))
-#define SN_HWPERF_IS_ROUTER(x)         (SN_HWPERF_IS_NL3ROUTER(x) ||           \
-                                               SN_HWPERF_IS_NL4ROUTER(x) ||    \
-                                               SN_HWPERF_IS_OLDROUTER(x))
-#define SN_HWPERF_FOREIGN(x)           ((x) && !(x)->sn_hwp_this_part && !(x)->sn_hwp_is_shared)
-#define SN_HWPERF_SAME_OBJTYPE(x,y)    ((SN_HWPERF_IS_NODE(x) && SN_HWPERF_IS_NODE(y)) ||\
-                                       (SN_HWPERF_IS_IONODE(x) && SN_HWPERF_IS_IONODE(y)) ||\
-                                       (SN_HWPERF_IS_ROUTER(x) && SN_HWPERF_IS_ROUTER(y)))
-
-/* numa port structure, SN_HWPERF_ENUM_PORTS returns an array of these */
-struct sn_hwperf_port_info {
-       u32 port;
-       u32 conn_id;
-       u32 conn_port;
-};
-
-/* for HWPERF_{GET,SET}_MMRS */
-struct sn_hwperf_data {
-       u64 addr;
-       u64 data;
-};
-
-/* user ioctl() argument, see below */
-struct sn_hwperf_ioctl_args {
-        u64 arg;               /* argument, usually an object id */
-        u64 sz;                 /* size of transfer */
-        void *ptr;              /* pointer to source/target */
-        u32 v0;                        /* second return value */
-};
-
-/*
- * For SN_HWPERF_{GET,SET}_MMRS and SN_HWPERF_OBJECT_DISTANCE,
- * sn_hwperf_ioctl_args.arg can be used to specify a CPU on which
- * to call SAL, and whether to use an interprocessor interrupt
- * or task migration in order to do so. If the CPU specified is
- * SN_HWPERF_ARG_ANY_CPU, then the current CPU will be used.
- */
-#define SN_HWPERF_ARG_ANY_CPU          0x7fffffffUL
-#define SN_HWPERF_ARG_CPU_MASK         0x7fffffff00000000ULL
-#define SN_HWPERF_ARG_USE_IPI_MASK     0x8000000000000000ULL
-#define SN_HWPERF_ARG_OBJID_MASK       0x00000000ffffffffULL
-
-/* 
- * ioctl requests on the "sn_hwperf" misc device that call SAL.
- */
-#define SN_HWPERF_OP_MEM_COPYIN                0x1000
-#define SN_HWPERF_OP_MEM_COPYOUT       0x2000
-#define SN_HWPERF_OP_MASK              0x0fff
-
-/*
- * Determine mem requirement.
- * arg don't care
- * sz  8
- * p   pointer to u64 integer
- */
-#define        SN_HWPERF_GET_HEAPSIZE          1
-
-/*
- * Install mem for SAL drvr
- * arg don't care
- * sz  sizeof buffer pointed to by p
- * p   pointer to buffer for scratch area
- */
-#define SN_HWPERF_INSTALL_HEAP         2
-
-/*
- * Determine number of objects
- * arg don't care
- * sz  8
- * p   pointer to u64 integer
- */
-#define SN_HWPERF_OBJECT_COUNT         (10|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Determine object "distance", relative to a cpu. This operation can
- * execute on a designated logical cpu number, using either an IPI or
- * via task migration. If the cpu number is SN_HWPERF_ANY_CPU, then
- * the current CPU is used. See the SN_HWPERF_ARG_* macros above.
- *
- * arg bitmap of IPI flag, cpu number and object id
- * sz  8
- * p   pointer to u64 integer
- */
-#define SN_HWPERF_OBJECT_DISTANCE      (11|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Enumerate objects. Special case if sz == 8, returns the required
- * buffer size.
- * arg don't care
- * sz  sizeof buffer pointed to by p
- * p   pointer to array of struct sn_hwperf_object_info
- */
-#define SN_HWPERF_ENUM_OBJECTS         (12|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Enumerate NumaLink ports for an object. Special case if sz == 8,
- * returns the required buffer size.
- * arg object id
- * sz  sizeof buffer pointed to by p
- * p   pointer to array of struct sn_hwperf_port_info
- */
-#define SN_HWPERF_ENUM_PORTS           (13|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * SET/GET memory mapped registers. These operations can execute
- * on a designated logical cpu number, using either an IPI or via
- * task migration. If the cpu number is SN_HWPERF_ANY_CPU, then
- * the current CPU is used. See the SN_HWPERF_ARG_* macros above.
- *
- * arg bitmap of ipi flag, cpu number and object id
- * sz  sizeof buffer pointed to by p
- * p   pointer to array of struct sn_hwperf_data
- */
-#define SN_HWPERF_SET_MMRS             (14|SN_HWPERF_OP_MEM_COPYIN)
-#define SN_HWPERF_GET_MMRS             (15|SN_HWPERF_OP_MEM_COPYOUT| \
-                                           SN_HWPERF_OP_MEM_COPYIN)
-/*
- * Lock a shared object
- * arg object id
- * sz  don't care
- * p   don't care
- */
-#define SN_HWPERF_ACQUIRE              16
-
-/*
- * Unlock a shared object
- * arg object id
- * sz  don't care
- * p   don't care
- */
-#define SN_HWPERF_RELEASE              17
-
-/*
- * Break a lock on a shared object
- * arg object id
- * sz  don't care
- * p   don't care
- */
-#define SN_HWPERF_FORCE_RELEASE                18
-
-/*
- * ioctl requests on "sn_hwperf" that do not call SAL
- */
-
-/*
- * get cpu info as an array of hwperf_object_info_t. 
- * id is logical CPU number, name is description, location
- * is geoid (e.g. 001c04#1c). Special case if sz == 8,
- * returns the required buffer size.
- *
- * arg don't care
- * sz  sizeof buffer pointed to by p
- * p   pointer to array of struct sn_hwperf_object_info
- */
-#define SN_HWPERF_GET_CPU_INFO         (100|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Given an object id, return it's node number (aka cnode).
- * arg object id
- * sz  8
- * p   pointer to u64 integer
- */
-#define SN_HWPERF_GET_OBJ_NODE         (101|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Given a node number (cnode), return it's nasid.
- * arg ordinal node number (aka cnodeid)
- * sz  8
- * p   pointer to u64 integer
- */
-#define SN_HWPERF_GET_NODE_NASID       (102|SN_HWPERF_OP_MEM_COPYOUT)
-
-/*
- * Given a node id, determine the id of the nearest node with CPUs
- * and the id of the nearest node that has memory. The argument
- * node would normally be a "headless" node, e.g. an "IO node".
- * Return 0 on success.
- */
-extern int sn_hwperf_get_nearest_node(cnodeid_t node,
-       cnodeid_t *near_mem, cnodeid_t *near_cpu);
-
-/* return codes */
-#define SN_HWPERF_OP_OK                        0
-#define SN_HWPERF_OP_NOMEM             1
-#define SN_HWPERF_OP_NO_PERM           2
-#define SN_HWPERF_OP_IO_ERROR          3
-#define SN_HWPERF_OP_BUSY              4
-#define SN_HWPERF_OP_RECONFIGURE       253
-#define SN_HWPERF_OP_INVAL             254
-
-int sn_topology_open(struct inode *inode, struct file *file);
-int sn_topology_release(struct inode *inode, struct file *file);
-#endif                         /* SN_HWPERF_H */
diff --git a/arch/ia64/include/asm/sn/sn_cpuid.h b/arch/ia64/include/asm/sn/sn_cpuid.h
deleted file mode 100644 (file)
index a676dd9..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* 
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-
-#ifndef _ASM_IA64_SN_SN_CPUID_H
-#define _ASM_IA64_SN_SN_CPUID_H
-
-#include <linux/smp.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/pda.h>
-#include <asm/intrinsics.h>
-
-
-/*
- * Functions for converting between cpuids, nodeids and NASIDs.
- * 
- * These are for SGI platforms only.
- *
- */
-
-
-
-
-/*
- *  Definitions of terms (these definitions are for IA64 ONLY. Other architectures
- *  use cpuid/cpunum quite defferently):
- *
- *        CPUID - a number in range of 0..NR_CPUS-1 that uniquely identifies
- *             the cpu. The value cpuid has no significance on IA64 other than
- *             the boot cpu is 0.
- *                     smp_processor_id() returns the cpuid of the current cpu.
- *
- *        CPU_PHYSICAL_ID (also known as HARD_PROCESSOR_ID)
- *             This is the same as 31:24 of the processor LID register
- *                     hard_smp_processor_id()- cpu_physical_id of current processor
- *                     cpu_physical_id(cpuid) - convert a <cpuid> to a <physical_cpuid>
- *                     cpu_logical_id(phy_id) - convert a <physical_cpuid> to a <cpuid> 
- *                             * not real efficient - don't use in perf critical code
- *
- *         SLICE - a number in the range of 0 - 3 (typically) that represents the
- *             cpu number on a brick.
- *
- *        SUBNODE - (almost obsolete) the number of the FSB that a cpu is
- *             connected to. This is also the same as the PI number. Usually 0 or 1.
- *
- *     NOTE!!!: the value of the bits in the cpu physical id (SAPICid or LID) of a cpu has no 
- *     significance. The SAPIC id (LID) is a 16-bit cookie that has meaning only to the PROM.
- *
- *
- * The macros convert between cpu physical ids & slice/nasid/cnodeid.
- * These terms are described below:
- *
- *
- * Brick
- *          -----   -----           -----   -----       CPU
- *          | 0 |   | 1 |           | 0 |   | 1 |       SLICE
- *          -----   -----           -----   -----
- *            |       |               |       |
- *            |       |               |       |
- *          0 |       | 2           0 |       | 2       FSB SLOT
- *             -------                 -------  
- *                |                       |
- *                |                       |
- *                |                       |
- *             ------------      -------------
- *             |          |      |           |
- *             |    SHUB  |      |   SHUB    |        NASID   (0..MAX_NASIDS)
- *             |          |----- |           |        CNODEID (0..num_compact_nodes-1)
- *             |          |      |           |
- *             |          |      |           |
- *             ------------      -------------
- *                   |                 |
- *                           
- *
- */
-
-#define get_node_number(addr)                  NASID_GET(addr)
-
-/*
- * NOTE: on non-MP systems, only cpuid 0 exists
- */
-
-extern short physical_node_map[];      /* indexed by nasid to get cnode */
-
-/*
- * Macros for retrieving info about current cpu
- */
-#define get_nasid()    (sn_nodepda->phys_cpuid[smp_processor_id()].nasid)
-#define get_subnode()  (sn_nodepda->phys_cpuid[smp_processor_id()].subnode)
-#define get_slice()    (sn_nodepda->phys_cpuid[smp_processor_id()].slice)
-#define get_cnode()    (sn_nodepda->phys_cpuid[smp_processor_id()].cnode)
-#define get_sapicid()  ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
-
-/*
- * Macros for retrieving info about an arbitrary cpu
- *     cpuid - logical cpu id
- */
-#define cpuid_to_nasid(cpuid)          (sn_nodepda->phys_cpuid[cpuid].nasid)
-#define cpuid_to_subnode(cpuid)                (sn_nodepda->phys_cpuid[cpuid].subnode)
-#define cpuid_to_slice(cpuid)          (sn_nodepda->phys_cpuid[cpuid].slice)
-
-
-/*
- * Dont use the following in performance critical code. They require scans
- * of potentially large tables.
- */
-extern int nasid_slice_to_cpuid(int, int);
-
-/*
- * cnodeid_to_nasid - convert a cnodeid to a NASID
- */
-#define cnodeid_to_nasid(cnodeid)      (sn_cnodeid_to_nasid[cnodeid])
-/*
- * nasid_to_cnodeid - convert a NASID to a cnodeid
- */
-#define nasid_to_cnodeid(nasid)                (physical_node_map[nasid])
-
-/*
- * partition_coherence_id - get the coherence ID of the current partition
- */
-extern u8 sn_coherency_id;
-#define partition_coherence_id()       (sn_coherency_id)
-
-#endif /* _ASM_IA64_SN_SN_CPUID_H */
-
diff --git a/arch/ia64/include/asm/sn/sn_feature_sets.h b/arch/ia64/include/asm/sn/sn_feature_sets.h
deleted file mode 100644 (file)
index 8e83ac1..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _ASM_IA64_SN_FEATURE_SETS_H
-#define _ASM_IA64_SN_FEATURE_SETS_H
-
-/*
- * SN PROM Features
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005-2006 Silicon Graphics, Inc.  All rights reserved.
- */
-
-
-/* --------------------- PROM Features -----------------------------*/
-extern int sn_prom_feature_available(int id);
-
-#define MAX_PROM_FEATURE_SETS                  2
-
-/*
- * The following defines features that may or may not be supported by the
- * current PROM. The OS uses sn_prom_feature_available(feature) to test for
- * the presence of a PROM feature. Down rev (old) PROMs will always test
- * "false" for new features.
- *
- * Use:
- *             if (sn_prom_feature_available(PRF_XXX))
- *                     ...
- */
-
-#define PRF_PAL_CACHE_FLUSH_SAFE       0
-#define PRF_DEVICE_FLUSH_LIST          1
-#define PRF_HOTPLUG_SUPPORT            2
-#define PRF_CPU_DISABLE_SUPPORT                3
-
-/* --------------------- OS Features -------------------------------*/
-
-/*
- * The following defines OS features that are optionally present in
- * the operating system.
- * During boot, PROM is notified of these features via a series of calls:
- *
- *             ia64_sn_set_os_feature(feature1);
- *
- * Once enabled, a feature cannot be disabled.
- *
- * By default, features are disabled unless explicitly enabled.
- *
- * These defines must be kept in sync with the corresponding
- * PROM definitions in feature_sets.h.
- */
-#define  OSF_MCA_SLV_TO_OS_INIT_SLV    0
-#define  OSF_FEAT_LOG_SBES             1
-#define  OSF_ACPI_ENABLE               2
-#define  OSF_PCISEGMENT_ENABLE         3
-
-
-#endif /* _ASM_IA64_SN_FEATURE_SETS_H */
index 1f5ff47..d437aa4 100644 (file)
  * Copyright (c) 2000-2006 Silicon Graphics, Inc.  All rights reserved.
  */
 
-
+#include <linux/types.h>
 #include <asm/sal.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/shub_mmr.h>
 
 // SGI Specific Calls
-#define  SN_SAL_POD_MODE                           0x02000001
-#define  SN_SAL_SYSTEM_RESET                       0x02000002
-#define  SN_SAL_PROBE                              0x02000003
-#define  SN_SAL_GET_MASTER_NASID                   0x02000004
-#define         SN_SAL_GET_KLCONFIG_ADDR                  0x02000005
-#define  SN_SAL_LOG_CE                            0x02000006
-#define  SN_SAL_REGISTER_CE                       0x02000007
 #define  SN_SAL_GET_PARTITION_ADDR                0x02000009
-#define  SN_SAL_XP_ADDR_REGION                    0x0200000f
-#define  SN_SAL_NO_FAULT_ZONE_VIRTUAL             0x02000010
-#define  SN_SAL_NO_FAULT_ZONE_PHYSICAL            0x02000011
-#define  SN_SAL_PRINT_ERROR                       0x02000012
-#define  SN_SAL_REGISTER_PMI_HANDLER              0x02000014
-#define  SN_SAL_SET_ERROR_HANDLING_FEATURES       0x0200001a   // reentrant
-#define  SN_SAL_GET_FIT_COMPT                     0x0200001b   // reentrant
-#define  SN_SAL_GET_SAPIC_INFO                     0x0200001d
-#define  SN_SAL_GET_SN_INFO                        0x0200001e
-#define  SN_SAL_CONSOLE_PUTC                       0x02000021
-#define  SN_SAL_CONSOLE_GETC                       0x02000022
-#define  SN_SAL_CONSOLE_PUTS                       0x02000023
-#define  SN_SAL_CONSOLE_GETS                       0x02000024
-#define  SN_SAL_CONSOLE_GETS_TIMEOUT               0x02000025
-#define  SN_SAL_CONSOLE_POLL                       0x02000026
-#define  SN_SAL_CONSOLE_INTR                       0x02000027
-#define  SN_SAL_CONSOLE_PUTB                      0x02000028
-#define  SN_SAL_CONSOLE_XMIT_CHARS                0x0200002a
-#define  SN_SAL_CONSOLE_READC                     0x0200002b
-#define  SN_SAL_SYSCTL_OP                         0x02000030
-#define  SN_SAL_SYSCTL_MODID_GET                  0x02000031
-#define  SN_SAL_SYSCTL_GET                         0x02000032
-#define  SN_SAL_SYSCTL_IOBRICK_MODULE_GET          0x02000033
-#define  SN_SAL_SYSCTL_IO_PORTSPEED_GET            0x02000035
-#define  SN_SAL_SYSCTL_SLAB_GET                    0x02000036
-#define  SN_SAL_BUS_CONFIG                        0x02000037
-#define  SN_SAL_SYS_SERIAL_GET                    0x02000038
-#define  SN_SAL_PARTITION_SERIAL_GET              0x02000039
-#define  SN_SAL_SYSCTL_PARTITION_GET               0x0200003a
-#define  SN_SAL_SYSTEM_POWER_DOWN                 0x0200003b
-#define  SN_SAL_GET_MASTER_BASEIO_NASID                   0x0200003c
-#define  SN_SAL_COHERENCE                          0x0200003d
 #define  SN_SAL_MEMPROTECT                         0x0200003e
-#define  SN_SAL_SYSCTL_FRU_CAPTURE                0x0200003f
-
-#define  SN_SAL_SYSCTL_IOBRICK_PCI_OP             0x02000042   // reentrant
-#define         SN_SAL_IROUTER_OP                         0x02000043
-#define  SN_SAL_SYSCTL_EVENT                       0x02000044
-#define  SN_SAL_IOIF_INTERRUPT                    0x0200004a
-#define  SN_SAL_HWPERF_OP                         0x02000050   // lock
-#define  SN_SAL_IOIF_ERROR_INTERRUPT              0x02000051
-#define  SN_SAL_IOIF_PCI_SAFE                     0x02000052
-#define  SN_SAL_IOIF_SLOT_ENABLE                  0x02000053
-#define  SN_SAL_IOIF_SLOT_DISABLE                 0x02000054
-#define  SN_SAL_IOIF_GET_HUBDEV_INFO              0x02000055
-#define  SN_SAL_IOIF_GET_PCIBUS_INFO              0x02000056
-#define  SN_SAL_IOIF_GET_PCIDEV_INFO              0x02000057
-#define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST     0x02000058   // deprecated
-#define  SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST     0x0200005a
-
-#define SN_SAL_IOIF_INIT                          0x0200005f
-#define SN_SAL_HUB_ERROR_INTERRUPT                0x02000060
-#define SN_SAL_BTE_RECOVER                        0x02000061
-#define SN_SAL_RESERVED_DO_NOT_USE                0x02000062
-#define SN_SAL_IOIF_GET_PCI_TOPOLOGY              0x02000064
-
-#define  SN_SAL_GET_PROM_FEATURE_SET              0x02000065
-#define  SN_SAL_SET_OS_FEATURE_SET                0x02000066
-#define  SN_SAL_INJECT_ERROR                      0x02000067
-#define  SN_SAL_SET_CPU_NUMBER                    0x02000068
 
-#define  SN_SAL_KERNEL_LAUNCH_EVENT               0x02000069
 #define  SN_SAL_WATCHLIST_ALLOC                           0x02000070
 #define  SN_SAL_WATCHLIST_FREE                    0x02000071
 
-/*
- * Service-specific constants
- */
-
-/* Console interrupt manipulation */
-       /* action codes */
-#define SAL_CONSOLE_INTR_OFF    0       /* turn the interrupt off */
-#define SAL_CONSOLE_INTR_ON     1       /* turn the interrupt on */
-#define SAL_CONSOLE_INTR_STATUS 2      /* retrieve the interrupt status */
-       /* interrupt specification & status return codes */
-#define SAL_CONSOLE_INTR_XMIT  1       /* output interrupt */
-#define SAL_CONSOLE_INTR_RECV  2       /* input interrupt */
-
-/* interrupt handling */
-#define SAL_INTR_ALLOC         1
-#define SAL_INTR_FREE          2
-#define SAL_INTR_REDIRECT      3
-
-/*
- * operations available on the generic SN_SAL_SYSCTL_OP
- * runtime service
- */
-#define SAL_SYSCTL_OP_IOBOARD          0x0001  /*  retrieve board type */
-#define SAL_SYSCTL_OP_TIO_JLCK_RST      0x0002  /* issue TIO clock reset */
-
-/*
- * IRouter (i.e. generalized system controller) operations
- */
-#define SAL_IROUTER_OPEN       0       /* open a subchannel */
-#define SAL_IROUTER_CLOSE      1       /* close a subchannel */
-#define SAL_IROUTER_SEND       2       /* send part of an IRouter packet */
-#define SAL_IROUTER_RECV       3       /* receive part of an IRouter packet */
-#define SAL_IROUTER_INTR_STATUS        4       /* check the interrupt status for
-                                        * an open subchannel
-                                        */
-#define SAL_IROUTER_INTR_ON    5       /* enable an interrupt */
-#define SAL_IROUTER_INTR_OFF   6       /* disable an interrupt */
-#define SAL_IROUTER_INIT       7       /* initialize IRouter driver */
-
-/* IRouter interrupt mask bits */
-#define SAL_IROUTER_INTR_XMIT  SAL_CONSOLE_INTR_XMIT
-#define SAL_IROUTER_INTR_RECV  SAL_CONSOLE_INTR_RECV
-
-/*
- * Error Handling Features
- */
-#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV    0x1     // obsolete
-#define SAL_ERR_FEAT_LOG_SBES                  0x2     // obsolete
-#define SAL_ERR_FEAT_MFR_OVERRIDE              0x4
-#define SAL_ERR_FEAT_SBE_THRESHOLD             0xffff0000
-
 /*
  * SAL Error Codes
  */
 #define SALRET_INVALID_ARG     (-2)
 #define SALRET_ERROR           (-3)
 
-#define SN_SAL_FAKE_PROM                          0x02009999
-
-/**
-  * sn_sal_revision - get the SGI SAL revision number
-  *
-  * The SGI PROM stores its version in the sal_[ab]_rev_(major|minor).
-  * This routine simply extracts the major and minor values and
-  * presents them in a u32 format.
-  *
-  * For example, version 4.05 would be represented at 0x0405.
-  */
-static inline u32
-sn_sal_rev(void)
-{
-       struct ia64_sal_systab *systab = __va(efi.sal_systab);
-
-       return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor);
-}
-
-/*
- * Returns the master console nasid, if the call fails, return an illegal
- * value.
- */
-static inline u64
-ia64_sn_get_console_nasid(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0);
-
-       if (ret_stuff.status < 0)
-               return ret_stuff.status;
-
-       /* Master console nasid is in 'v0' */
-       return ret_stuff.v0;
-}
-
-/*
- * Returns the master baseio nasid, if the call fails, return an illegal
- * value.
- */
-static inline u64
-ia64_sn_get_master_baseio_nasid(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0);
-
-       if (ret_stuff.status < 0)
-               return ret_stuff.status;
-
-       /* Master baseio nasid is in 'v0' */
-       return ret_stuff.v0;
-}
-
-static inline void *
-ia64_sn_get_klconfig_addr(nasid_t nasid)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, (u64)nasid, 0, 0, 0, 0, 0, 0);
-       return ret_stuff.v0 ? __va(ret_stuff.v0) : NULL;
-}
-
-/*
- * Returns the next console character.
- */
-static inline u64
-ia64_sn_console_getc(int *ch)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0);
-
-       /* character is in 'v0' */
-       *ch = (int)ret_stuff.v0;
-
-       return ret_stuff.status;
-}
-
-/*
- * Read a character from the SAL console device, after a previous interrupt
- * or poll operation has given us to know that a character is available
- * to be read.
- */
-static inline u64
-ia64_sn_console_readc(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_READC, 0, 0, 0, 0, 0, 0, 0);
-
-       /* character is in 'v0' */
-       return ret_stuff.v0;
-}
-
-/*
- * Sends the given character to the console.
- */
-static inline u64
-ia64_sn_console_putc(char ch)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (u64)ch, 0, 0, 0, 0, 0, 0);
-
-       return ret_stuff.status;
-}
-
-/*
- * Sends the given buffer to the console.
- */
-static inline u64
-ia64_sn_console_putb(const char *buf, int len)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0; 
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (u64)buf, (u64)len, 0, 0, 0, 0, 0);
-
-       if ( ret_stuff.status == 0 ) {
-               return ret_stuff.v0;
-       }
-       return (u64)0;
-}
-
-/*
- * Print a platform error record
- */
-static inline u64
-ia64_sn_plat_specific_err_print(int (*hook)(const char*, ...), char *rec)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_REENTRANT(ret_stuff, SN_SAL_PRINT_ERROR, (u64)hook, (u64)rec, 0, 0, 0, 0, 0);
-
-       return ret_stuff.status;
-}
-
-/*
- * Check for Platform errors
- */
-static inline u64
-ia64_sn_plat_cpei_handler(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0);
-
-       return ret_stuff.status;
-}
-
-/*
- * Set Error Handling Features (Obsolete)
- */
-static inline u64
-ia64_sn_plat_set_error_handling_features(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES,
-               SAL_ERR_FEAT_LOG_SBES,
-               0, 0, 0, 0, 0, 0);
-
-       return ret_stuff.status;
-}
-
-/*
- * Checks for console input.
- */
-static inline u64
-ia64_sn_console_check(int *result)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0);
-
-       /* result is in 'v0' */
-       *result = (int)ret_stuff.v0;
-
-       return ret_stuff.status;
-}
-
-/*
- * Checks console interrupt status
- */
-static inline u64
-ia64_sn_console_intr_status(void)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, 
-                0, SAL_CONSOLE_INTR_STATUS,
-                0, 0, 0, 0, 0);
-
-       if (ret_stuff.status == 0) {
-           return ret_stuff.v0;
-       }
-       
-       return 0;
-}
-
-/*
- * Enable an interrupt on the SAL console device.
- */
-static inline void
-ia64_sn_console_intr_enable(u64 intr)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, 
-                intr, SAL_CONSOLE_INTR_ON,
-                0, 0, 0, 0, 0);
-}
-
-/*
- * Disable an interrupt on the SAL console device.
- */
-static inline void
-ia64_sn_console_intr_disable(u64 intr)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, 
-                intr, SAL_CONSOLE_INTR_OFF,
-                0, 0, 0, 0, 0);
-}
-
-/*
- * Sends a character buffer to the console asynchronously.
- */
-static inline u64
-ia64_sn_console_xmit_chars(char *buf, int len)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_XMIT_CHARS,
-                (u64)buf, (u64)len,
-                0, 0, 0, 0, 0);
-
-       if (ret_stuff.status == 0) {
-           return ret_stuff.v0;
-       }
-
-       return 0;
-}
-
-/*
- * Returns the iobrick module Id
- */
-static inline u64
-ia64_sn_sysctl_iobrick_module_get(nasid_t nasid, int *result)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0);
-
-       /* result is in 'v0' */
-       *result = (int)ret_stuff.v0;
-
-       return ret_stuff.status;
-}
-
-/**
- * ia64_sn_pod_mode - call the SN_SAL_POD_MODE function
- *
- * SN_SAL_POD_MODE actually takes an argument, but it's always
- * 0 when we call it from the kernel, so we don't have to expose
- * it to the caller.
- */
-static inline u64
-ia64_sn_pod_mode(void)
-{
-       struct ia64_sal_retval isrv;
-       SAL_CALL_REENTRANT(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0);
-       if (isrv.status)
-               return 0;
-       return isrv.v0;
-}
-
-/**
- * ia64_sn_probe_mem - read from memory safely
- * @addr: address to probe
- * @size: number bytes to read (1,2,4,8)
- * @data_ptr: address to store value read by probe (-1 returned if probe fails)
- *
- * Call into the SAL to do a memory read.  If the read generates a machine
- * check, this routine will recover gracefully and return -1 to the caller.
- * @addr is usually a kernel virtual address in uncached space (i.e. the
- * address starts with 0xc), but if called in physical mode, @addr should
- * be a physical address.
- *
- * Return values:
- *  0 - probe successful
- *  1 - probe failed (generated MCA)
- *  2 - Bad arg
- * <0 - PAL error
- */
-static inline u64
-ia64_sn_probe_mem(long addr, long size, void *data_ptr)
-{
-       struct ia64_sal_retval isrv;
-
-       SAL_CALL(isrv, SN_SAL_PROBE, addr, size, 0, 0, 0, 0, 0);
-
-       if (data_ptr) {
-               switch (size) {
-               case 1:
-                       *((u8*)data_ptr) = (u8)isrv.v0;
-                       break;
-               case 2:
-                       *((u16*)data_ptr) = (u16)isrv.v0;
-                       break;
-               case 4:
-                       *((u32*)data_ptr) = (u32)isrv.v0;
-                       break;
-               case 8:
-                       *((u64*)data_ptr) = (u64)isrv.v0;
-                       break;
-               default:
-                       isrv.status = 2;
-               }
-       }
-       return isrv.status;
-}
-
-/*
- * Retrieve the system serial number as an ASCII string.
- */
-static inline u64
-ia64_sn_sys_serial_get(char *buf)
-{
-       struct ia64_sal_retval ret_stuff;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-extern char sn_system_serial_number_string[];
-extern u64 sn_partition_serial_number;
-
-static inline char *
-sn_system_serial_number(void) {
-       if (sn_system_serial_number_string[0]) {
-               return(sn_system_serial_number_string);
-       } else {
-               ia64_sn_sys_serial_get(sn_system_serial_number_string);
-               return(sn_system_serial_number_string);
-       }
-}
-       
-
-/*
- * Returns a unique id number for this system and partition (suitable for
- * use with license managers), based in part on the system serial number.
- */
-static inline u64
-ia64_sn_partition_serial_get(void)
-{
-       struct ia64_sal_retval ret_stuff;
-       ia64_sal_oemcall_reentrant(&ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0,
-                                  0, 0, 0, 0, 0, 0);
-       if (ret_stuff.status != 0)
-           return 0;
-       return ret_stuff.v0;
-}
-
-static inline u64
-sn_partition_serial_number_val(void) {
-       if (unlikely(sn_partition_serial_number == 0)) {
-               sn_partition_serial_number = ia64_sn_partition_serial_get();
-       }
-       return sn_partition_serial_number;
-}
-
-/*
- * Returns the partition id of the nasid passed in as an argument,
- * or INVALID_PARTID if the partition id cannot be retrieved.
- */
-static inline partid_t
-ia64_sn_sysctl_partition_get(nasid_t nasid)
-{
-       struct ia64_sal_retval ret_stuff;
-       SAL_CALL(ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
-               0, 0, 0, 0, 0, 0);
-       if (ret_stuff.status != 0)
-           return -1;
-       return ((partid_t)ret_stuff.v0);
-}
-
 /*
  * Returns the physical address of the partition's reserved page through
  * an iterative number of calls.
@@ -633,96 +58,6 @@ sn_partition_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
        return rv.status;
 }
 
-/*
- * Register or unregister a physical address range being referenced across
- * a partition boundary for which certain SAL errors should be scanned for,
- * cleaned up and ignored.  This is of value for kernel partitioning code only.
- * Values for the operation argument:
- *     1 = register this address range with SAL
- *     0 = unregister this address range with SAL
- * 
- * SAL maintains a reference count on an address range in case it is registered
- * multiple times.
- * 
- * On success, returns the reference count of the address range after the SAL
- * call has performed the current registration/unregistration.  Returns a
- * negative value if an error occurred.
- */
-static inline int
-sn_register_xp_addr_region(u64 paddr, u64 len, int operation)
-{
-       struct ia64_sal_retval ret_stuff;
-       ia64_sal_oemcall(&ret_stuff, SN_SAL_XP_ADDR_REGION, paddr, len,
-                        (u64)operation, 0, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-/*
- * Register or unregister an instruction range for which SAL errors should
- * be ignored.  If an error occurs while in the registered range, SAL jumps
- * to return_addr after ignoring the error.  Values for the operation argument:
- *     1 = register this instruction range with SAL
- *     0 = unregister this instruction range with SAL
- *
- * Returns 0 on success, or a negative value if an error occurred.
- */
-static inline int
-sn_register_nofault_code(u64 start_addr, u64 end_addr, u64 return_addr,
-                        int virtual, int operation)
-{
-       struct ia64_sal_retval ret_stuff;
-       u64 call;
-       if (virtual) {
-               call = SN_SAL_NO_FAULT_ZONE_VIRTUAL;
-       } else {
-               call = SN_SAL_NO_FAULT_ZONE_PHYSICAL;
-       }
-       ia64_sal_oemcall(&ret_stuff, call, start_addr, end_addr, return_addr,
-                        (u64)1, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-/*
- * Register or unregister a function to handle a PMI received by a CPU.
- * Before calling the registered handler, SAL sets r1 to the value that
- * was passed in as the global_pointer.
- *
- * If the handler pointer is NULL, then the currently registered handler
- * will be unregistered.
- *
- * Returns 0 on success, or a negative value if an error occurred.
- */
-static inline int
-sn_register_pmi_handler(u64 handler, u64 global_pointer)
-{
-       struct ia64_sal_retval ret_stuff;
-       ia64_sal_oemcall(&ret_stuff, SN_SAL_REGISTER_PMI_HANDLER, handler,
-                        global_pointer, 0, 0, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-/*
- * Change or query the coherence domain for this partition. Each cpu-based
- * nasid is represented by a bit in an array of 64-bit words:
- *      0 = not in this partition's coherency domain
- *      1 = in this partition's coherency domain
- *
- * It is not possible for the local system's nasids to be removed from
- * the coherency domain.  Purpose of the domain arguments:
- *      new_domain = set the coherence domain to the given nasids
- *      old_domain = return the current coherence domain
- *
- * Returns 0 on success, or a negative value if an error occurred.
- */
-static inline int
-sn_change_coherence(u64 *new_domain, u64 *old_domain)
-{
-       struct ia64_sal_retval ret_stuff;
-       ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_COHERENCE, (u64)new_domain,
-                               (u64)old_domain, 0, 0, 0, 0, 0);
-       return ret_stuff.status;
-}
-
 /*
  * Change memory access protections for a physical address range.
  * nasid_array is not used on Altix, but may be in future architectures.
@@ -744,450 +79,6 @@ sn_change_memprotect(u64 paddr, u64 len, u64 perms, u64 *nasid_array)
 #define SN_MEMPROT_ACCESS_CLASS_6              0x084080
 #define SN_MEMPROT_ACCESS_CLASS_7              0x021080
 
-/*
- * Turns off system power.
- */
-static inline void
-ia64_sn_power_down(void)
-{
-       struct ia64_sal_retval ret_stuff;
-       SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0);
-       while(1)
-               cpu_relax();
-       /* never returns */
-}
-
-/**
- * ia64_sn_fru_capture - tell the system controller to capture hw state
- *
- * This routine will call the SAL which will tell the system controller(s)
- * to capture hw mmr information from each SHub in the system.
- */
-static inline u64
-ia64_sn_fru_capture(void)
-{
-        struct ia64_sal_retval isrv;
-        SAL_CALL(isrv, SN_SAL_SYSCTL_FRU_CAPTURE, 0, 0, 0, 0, 0, 0, 0);
-        if (isrv.status)
-                return 0;
-        return isrv.v0;
-}
-
-/*
- * Performs an operation on a PCI bus or slot -- power up, power down
- * or reset.
- */
-static inline u64
-ia64_sn_sysctl_iobrick_pci_op(nasid_t n, u64 connection_type, 
-                             u64 bus, char slot, 
-                             u64 action)
-{
-       struct ia64_sal_retval rv = {0, 0, 0, 0};
-
-       SAL_CALL_NOLOCK(rv, SN_SAL_SYSCTL_IOBRICK_PCI_OP, connection_type, n, action,
-                bus, (u64) slot, 0, 0);
-       if (rv.status)
-               return rv.v0;
-       return 0;
-}
-
-
-/*
- * Open a subchannel for sending arbitrary data to the system
- * controller network via the system controller device associated with
- * 'nasid'.  Return the subchannel number or a negative error code.
- */
-static inline int
-ia64_sn_irtr_open(nasid_t nasid)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_OPEN, nasid,
-                          0, 0, 0, 0, 0);
-       return (int) rv.v0;
-}
-
-/*
- * Close system controller subchannel 'subch' previously opened on 'nasid'.
- */
-static inline int
-ia64_sn_irtr_close(nasid_t nasid, int subch)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_CLOSE,
-                          (u64) nasid, (u64) subch, 0, 0, 0, 0);
-       return (int) rv.status;
-}
-
-/*
- * Read data from system controller associated with 'nasid' on
- * subchannel 'subch'.  The buffer to be filled is pointed to by
- * 'buf', and its capacity is in the integer pointed to by 'len'.  The
- * referent of 'len' is set to the number of bytes read by the SAL
- * call.  The return value is either SALRET_OK (for bytes read) or
- * SALRET_ERROR (for error or "no data available").
- */
-static inline int
-ia64_sn_irtr_recv(nasid_t nasid, int subch, char *buf, int *len)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_RECV,
-                          (u64) nasid, (u64) subch, (u64) buf, (u64) len,
-                          0, 0);
-       return (int) rv.status;
-}
-
-/*
- * Write data to the system controller network via the system
- * controller associated with 'nasid' on suchannel 'subch'.  The
- * buffer to be written out is pointed to by 'buf', and 'len' is the
- * number of bytes to be written.  The return value is either the
- * number of bytes written (which could be zero) or a negative error
- * code.
- */
-static inline int
-ia64_sn_irtr_send(nasid_t nasid, int subch, char *buf, int len)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_SEND,
-                          (u64) nasid, (u64) subch, (u64) buf, (u64) len,
-                          0, 0);
-       return (int) rv.v0;
-}
-
-/*
- * Check whether any interrupts are pending for the system controller
- * associated with 'nasid' and its subchannel 'subch'.  The return
- * value is a mask of pending interrupts (SAL_IROUTER_INTR_XMIT and/or
- * SAL_IROUTER_INTR_RECV).
- */
-static inline int
-ia64_sn_irtr_intr(nasid_t nasid, int subch)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_STATUS,
-                          (u64) nasid, (u64) subch, 0, 0, 0, 0);
-       return (int) rv.v0;
-}
-
-/*
- * Enable the interrupt indicated by the intr parameter (either
- * SAL_IROUTER_INTR_XMIT or SAL_IROUTER_INTR_RECV).
- */
-static inline int
-ia64_sn_irtr_intr_enable(nasid_t nasid, int subch, u64 intr)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_ON,
-                          (u64) nasid, (u64) subch, intr, 0, 0, 0);
-       return (int) rv.v0;
-}
-
-/*
- * Disable the interrupt indicated by the intr parameter (either
- * SAL_IROUTER_INTR_XMIT or SAL_IROUTER_INTR_RECV).
- */
-static inline int
-ia64_sn_irtr_intr_disable(nasid_t nasid, int subch, u64 intr)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INTR_OFF,
-                          (u64) nasid, (u64) subch, intr, 0, 0, 0);
-       return (int) rv.v0;
-}
-
-/*
- * Set up a node as the point of contact for system controller
- * environmental event delivery.
- */
-static inline int
-ia64_sn_sysctl_event_init(nasid_t nasid)
-{
-        struct ia64_sal_retval rv;
-        SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_EVENT, (u64) nasid,
-                          0, 0, 0, 0, 0, 0);
-        return (int) rv.v0;
-}
-
-/*
- * Ask the system controller on the specified nasid to reset
- * the CX corelet clock.  Only valid on TIO nodes.
- */
-static inline int
-ia64_sn_sysctl_tio_clock_reset(nasid_t nasid)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_TIO_JLCK_RST,
-                       nasid, 0, 0, 0, 0, 0);
-       if (rv.status != 0)
-               return (int)rv.status;
-       if (rv.v0 != 0)
-               return (int)rv.v0;
-
-       return 0;
-}
-
-/*
- * Get the associated ioboard type for a given nasid.
- */
-static inline long
-ia64_sn_sysctl_ioboard_get(nasid_t nasid, u16 *ioboard)
-{
-       struct ia64_sal_retval isrv;
-       SAL_CALL_REENTRANT(isrv, SN_SAL_SYSCTL_OP, SAL_SYSCTL_OP_IOBOARD,
-                          nasid, 0, 0, 0, 0, 0);
-       if (isrv.v0 != 0) {
-               *ioboard = isrv.v0;
-               return isrv.status;
-       }
-       if (isrv.v1 != 0) {
-               *ioboard = isrv.v1;
-               return isrv.status;
-       }
-
-       return isrv.status;
-}
-
-/**
- * ia64_sn_get_fit_compt - read a FIT entry from the PROM header
- * @nasid: NASID of node to read
- * @index: FIT entry index to be retrieved (0..n)
- * @fitentry: 16 byte buffer where FIT entry will be stored.
- * @banbuf: optional buffer for retrieving banner
- * @banlen: length of banner buffer
- *
- * Access to the physical PROM chips needs to be serialized since reads and
- * writes can't occur at the same time, so we need to call into the SAL when
- * we want to look at the FIT entries on the chips.
- *
- * Returns:
- *     %SALRET_OK if ok
- *     %SALRET_INVALID_ARG if index too big
- *     %SALRET_NOT_IMPLEMENTED if running on older PROM
- *     ??? if nasid invalid OR banner buffer not large enough
- */
-static inline int
-ia64_sn_get_fit_compt(u64 nasid, u64 index, void *fitentry, void *banbuf,
-                     u64 banlen)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_GET_FIT_COMPT, nasid, index, fitentry,
-                       banbuf, banlen, 0, 0);
-       return (int) rv.status;
-}
-
-/*
- * Initialize the SAL components of the system controller
- * communication driver; specifically pass in a sizable buffer that
- * can be used for allocation of subchannel queues as new subchannels
- * are opened.  "buf" points to the buffer, and "len" specifies its
- * length.
- */
-static inline int
-ia64_sn_irtr_init(nasid_t nasid, void *buf, int len)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_REENTRANT(rv, SN_SAL_IROUTER_OP, SAL_IROUTER_INIT,
-                          (u64) nasid, (u64) buf, (u64) len, 0, 0, 0);
-       return (int) rv.status;
-}
-
-/*
- * Returns the nasid, subnode & slice corresponding to a SAPIC ID
- *
- *  In:
- *     arg0 - SN_SAL_GET_SAPIC_INFO
- *     arg1 - sapicid (lid >> 16) 
- *  Out:
- *     v0 - nasid
- *     v1 - subnode
- *     v2 - slice
- */
-static inline u64
-ia64_sn_get_sapic_info(int sapicid, int *nasid, int *subnode, int *slice)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SAPIC_INFO, sapicid, 0, 0, 0, 0, 0, 0);
-
-/***** BEGIN HACK - temp til old proms no longer supported ********/
-       if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) {
-               if (nasid) *nasid = sapicid & 0xfff;
-               if (subnode) *subnode = (sapicid >> 13) & 1;
-               if (slice) *slice = (sapicid >> 12) & 3;
-               return 0;
-       }
-/***** END HACK *******/
-
-       if (ret_stuff.status < 0)
-               return ret_stuff.status;
-
-       if (nasid) *nasid = (int) ret_stuff.v0;
-       if (subnode) *subnode = (int) ret_stuff.v1;
-       if (slice) *slice = (int) ret_stuff.v2;
-       return 0;
-}
-/*
- * Returns information about the HUB/SHUB.
- *  In:
- *     arg0 - SN_SAL_GET_SN_INFO
- *     arg1 - 0 (other values reserved for future use)
- *  Out:
- *     v0 
- *             [7:0]   - shub type (0=shub1, 1=shub2)
- *             [15:8]  - Log2 max number of nodes in entire system (includes
- *                       C-bricks, I-bricks, etc)
- *             [23:16] - Log2 of nodes per sharing domain                       
- *             [31:24] - partition ID
- *             [39:32] - coherency_id
- *             [47:40] - regionsize
- *     v1 
- *             [15:0]  - nasid mask (ex., 0x7ff for 11 bit nasid)
- *             [23:15] - bit position of low nasid bit
- */
-static inline u64
-ia64_sn_get_sn_info(int fc, u8 *shubtype, u16 *nasid_bitmask, u8 *nasid_shift, 
-               u8 *systemsize, u8 *sharing_domain_size, u8 *partid, u8 *coher, u8 *reg)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       ret_stuff.v1 = 0;
-       ret_stuff.v2 = 0;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, fc, 0, 0, 0, 0, 0, 0);
-
-/***** BEGIN HACK - temp til old proms no longer supported ********/
-       if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) {
-               int nasid = get_sapicid() & 0xfff;
-#define SH_SHUB_ID_NODES_PER_BIT_MASK 0x001f000000000000UL
-#define SH_SHUB_ID_NODES_PER_BIT_SHFT 48
-               if (shubtype) *shubtype = 0;
-               if (nasid_bitmask) *nasid_bitmask = 0x7ff;
-               if (nasid_shift) *nasid_shift = 38;
-               if (systemsize) *systemsize = 10;
-               if (sharing_domain_size) *sharing_domain_size = 8;
-               if (partid) *partid = ia64_sn_sysctl_partition_get(nasid);
-               if (coher) *coher = nasid >> 9;
-               if (reg) *reg = (HUB_L((u64 *) LOCAL_MMR_ADDR(SH1_SHUB_ID)) & SH_SHUB_ID_NODES_PER_BIT_MASK) >>
-                       SH_SHUB_ID_NODES_PER_BIT_SHFT;
-               return 0;
-       }
-/***** END HACK *******/
-
-       if (ret_stuff.status < 0)
-               return ret_stuff.status;
-
-       if (shubtype) *shubtype = ret_stuff.v0 & 0xff;
-       if (systemsize) *systemsize = (ret_stuff.v0 >> 8) & 0xff;
-       if (sharing_domain_size) *sharing_domain_size = (ret_stuff.v0 >> 16) & 0xff;
-       if (partid) *partid = (ret_stuff.v0 >> 24) & 0xff;
-       if (coher) *coher = (ret_stuff.v0 >> 32) & 0xff;
-       if (reg) *reg = (ret_stuff.v0 >> 40) & 0xff;
-       if (nasid_bitmask) *nasid_bitmask = (ret_stuff.v1 & 0xffff);
-       if (nasid_shift) *nasid_shift = (ret_stuff.v1 >> 16) & 0xff;
-       return 0;
-}
-/*
- * This is the access point to the Altix PROM hardware performance
- * and status monitoring interface. For info on using this, see
- * arch/ia64/include/asm/sn/sn2/sn_hwperf.h
- */
-static inline int
-ia64_sn_hwperf_op(nasid_t nasid, u64 opcode, u64 a0, u64 a1, u64 a2,
-                  u64 a3, u64 a4, int *v0)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_HWPERF_OP, (u64)nasid,
-               opcode, a0, a1, a2, a3, a4);
-       if (v0)
-               *v0 = (int) rv.v0;
-       return (int) rv.status;
-}
-
-static inline int
-ia64_sn_ioif_get_pci_topology(u64 buf, u64 len)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_IOIF_GET_PCI_TOPOLOGY, buf, len, 0, 0, 0, 0, 0);
-       return (int) rv.status;
-}
-
-/*
- * BTE error recovery is implemented in SAL
- */
-static inline int
-ia64_sn_bte_recovery(nasid_t nasid)
-{
-       struct ia64_sal_retval rv;
-
-       rv.status = 0;
-       SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, (u64)nasid, 0, 0, 0, 0, 0, 0);
-       if (rv.status == SALRET_NOT_IMPLEMENTED)
-               return 0;
-       return (int) rv.status;
-}
-
-static inline int
-ia64_sn_is_fake_prom(void)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_FAKE_PROM, 0, 0, 0, 0, 0, 0, 0);
-       return (rv.status == 0);
-}
-
-static inline int
-ia64_sn_get_prom_feature_set(int set, unsigned long *feature_set)
-{
-       struct ia64_sal_retval rv;
-
-       SAL_CALL_NOLOCK(rv, SN_SAL_GET_PROM_FEATURE_SET, set, 0, 0, 0, 0, 0, 0);
-       if (rv.status != 0)
-               return rv.status;
-       *feature_set = rv.v0;
-       return 0;
-}
-
-static inline int
-ia64_sn_set_os_feature(int feature)
-{
-       struct ia64_sal_retval rv;
-
-       SAL_CALL_NOLOCK(rv, SN_SAL_SET_OS_FEATURE_SET, feature, 0, 0, 0, 0, 0, 0);
-       return rv.status;
-}
-
-static inline int
-sn_inject_error(u64 paddr, u64 *data, u64 *ecc)
-{
-       struct ia64_sal_retval ret_stuff;
-
-       ia64_sal_oemcall_nolock(&ret_stuff, SN_SAL_INJECT_ERROR, paddr, (u64)data,
-                               (u64)ecc, 0, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-static inline int
-ia64_sn_set_cpu_number(int cpu)
-{
-       struct ia64_sal_retval rv;
-
-       SAL_CALL_NOLOCK(rv, SN_SAL_SET_CPU_NUMBER, cpu, 0, 0, 0, 0, 0, 0);
-       return rv.status;
-}
-static inline int
-ia64_sn_kernel_launch_event(void)
-{
-       struct ia64_sal_retval rv;
-       SAL_CALL_NOLOCK(rv, SN_SAL_KERNEL_LAUNCH_EVENT, 0, 0, 0, 0, 0, 0, 0);
-       return rv.status;
-}
-
 union sn_watchlist_u {
        u64     val;
        struct {
diff --git a/arch/ia64/include/asm/sn/tioca.h b/arch/ia64/include/asm/sn/tioca.h
deleted file mode 100644 (file)
index 666222d..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-#ifndef _ASM_IA64_SN_TIO_TIOCA_H
-#define _ASM_IA64_SN_TIO_TIOCA_H
-
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-
-#define TIOCA_PART_NUM 0xE020
-#define TIOCA_MFGR_NUM 0x24
-#define TIOCA_REV_A    0x1
-
-/*
- * Register layout for TIO:CA.  See below for bitmasks for each register.
- */
-
-struct tioca {
-       u64     ca_id;                          /* 0x000000 */
-       u64     ca_control1;                    /* 0x000008 */
-       u64     ca_control2;                    /* 0x000010 */
-       u64     ca_status1;                     /* 0x000018 */
-       u64     ca_status2;                     /* 0x000020 */
-       u64     ca_gart_aperature;              /* 0x000028 */
-       u64     ca_gfx_detach;                  /* 0x000030 */
-       u64     ca_inta_dest_addr;              /* 0x000038 */
-       u64     ca_intb_dest_addr;              /* 0x000040 */
-       u64     ca_err_int_dest_addr;           /* 0x000048 */
-       u64     ca_int_status;                  /* 0x000050 */
-       u64     ca_int_status_alias;            /* 0x000058 */
-       u64     ca_mult_error;                  /* 0x000060 */
-       u64     ca_mult_error_alias;            /* 0x000068 */
-       u64     ca_first_error;                 /* 0x000070 */
-       u64     ca_int_mask;                    /* 0x000078 */
-       u64     ca_crm_pkterr_type;             /* 0x000080 */
-       u64     ca_crm_pkterr_type_alias;       /* 0x000088 */
-       u64     ca_crm_ct_error_detail_1;       /* 0x000090 */
-       u64     ca_crm_ct_error_detail_2;       /* 0x000098 */
-       u64     ca_crm_tnumto;                  /* 0x0000A0 */
-       u64     ca_gart_err;                    /* 0x0000A8 */
-       u64     ca_pcierr_type;                 /* 0x0000B0 */
-       u64     ca_pcierr_addr;                 /* 0x0000B8 */
-
-       u64     ca_pad_0000C0[3];               /* 0x0000{C0..D0} */
-
-       u64     ca_pci_rd_buf_flush;            /* 0x0000D8 */
-       u64     ca_pci_dma_addr_extn;           /* 0x0000E0 */
-       u64     ca_agp_dma_addr_extn;           /* 0x0000E8 */
-       u64     ca_force_inta;                  /* 0x0000F0 */
-       u64     ca_force_intb;                  /* 0x0000F8 */
-       u64     ca_debug_vector_sel;            /* 0x000100 */
-       u64     ca_debug_mux_core_sel;          /* 0x000108 */
-       u64     ca_debug_mux_pci_sel;           /* 0x000110 */
-       u64     ca_debug_domain_sel;            /* 0x000118 */
-
-       u64     ca_pad_000120[28];              /* 0x0001{20..F8} */
-
-       u64     ca_gart_ptr_table;              /* 0x200 */
-       u64     ca_gart_tlb_addr[8];            /* 0x2{08..40} */
-};
-
-/*
- * Mask/shift definitions for TIO:CA registers.  The convention here is
- * to mainly use the names as they appear in the "TIO AEGIS Programmers'
- * Reference" with a CA_ prefix added.  Some exceptions were made to fix
- * duplicate field names or to generalize fields that are common to
- * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for
- * example).
- *
- * Fields consisting of a single bit have a single #define have a single
- * macro declaration to mask the bit.  Fields consisting of multiple bits
- * have two declarations: one to mask the proper bits in a register, and 
- * a second with the suffix "_SHFT" to identify how far the mask needs to
- * be shifted right to get its base value.
- */
-
-/* ==== ca_control1 */
-#define CA_SYS_BIG_END                 (1ull << 0)
-#define CA_DMA_AGP_SWAP                        (1ull << 1)
-#define CA_DMA_PCI_SWAP                        (1ull << 2)
-#define CA_PIO_IO_SWAP                 (1ull << 3)
-#define CA_PIO_MEM_SWAP                        (1ull << 4)
-#define CA_GFX_WR_SWAP                 (1ull << 5)
-#define CA_AGP_FW_ENABLE               (1ull << 6)
-#define CA_AGP_CAL_CYCLE               (0x7ull << 7)
-#define CA_AGP_CAL_CYCLE_SHFT          7
-#define CA_AGP_CAL_PRSCL_BYP           (1ull << 10)
-#define CA_AGP_INIT_CAL_ENB            (1ull << 11)
-#define CA_INJ_ADDR_PERR               (1ull << 12)
-#define CA_INJ_DATA_PERR               (1ull << 13)
-       /* bits 15:14 unused */
-#define CA_PCIM_IO_NBE_AD              (0x7ull << 16)
-#define CA_PCIM_IO_NBE_AD_SHFT         16
-#define CA_PCIM_FAST_BTB_ENB           (1ull << 19)
-       /* bits 23:20 unused */
-#define CA_PIO_ADDR_OFFSET             (0xffull << 24)
-#define CA_PIO_ADDR_OFFSET_SHFT                24
-       /* bits 35:32 unused */
-#define CA_AGPDMA_OP_COMBDELAY         (0x1full << 36)
-#define CA_AGPDMA_OP_COMBDELAY_SHFT    36
-       /* bit 41 unused */
-#define CA_AGPDMA_OP_ENB_COMBDELAY     (1ull << 42)
-#define        CA_PCI_INT_LPCNT                (0xffull << 44)
-#define CA_PCI_INT_LPCNT_SHFT          44
-       /* bits 63:52 unused */
-
-/* ==== ca_control2 */
-#define CA_AGP_LATENCY_TO              (0xffull << 0)
-#define CA_AGP_LATENCY_TO_SHFT         0
-#define CA_PCI_LATENCY_TO              (0xffull << 8)
-#define CA_PCI_LATENCY_TO_SHFT         8
-#define CA_PCI_MAX_RETRY               (0x3ffull << 16)
-#define CA_PCI_MAX_RETRY_SHFT          16
-       /* bits 27:26 unused */
-#define CA_RT_INT_EN                   (0x3ull << 28)
-#define CA_RT_INT_EN_SHFT                      28
-#define CA_MSI_INT_ENB                 (1ull << 30)
-#define CA_PCI_ARB_ERR_ENB             (1ull << 31)
-#define CA_GART_MEM_PARAM              (0x3ull << 32)
-#define CA_GART_MEM_PARAM_SHFT         32
-#define CA_GART_RD_PREFETCH_ENB                (1ull << 34)
-#define CA_GART_WR_PREFETCH_ENB                (1ull << 35)
-#define CA_GART_FLUSH_TLB              (1ull << 36)
-       /* bits 39:37 unused */
-#define CA_CRM_TNUMTO_PERIOD           (0x1fffull << 40)
-#define CA_CRM_TNUMTO_PERIOD_SHFT      40
-       /* bits 55:53 unused */
-#define CA_CRM_TNUMTO_ENB              (1ull << 56)
-#define CA_CRM_PRESCALER_BYP           (1ull << 57)
-       /* bits 59:58 unused */
-#define CA_CRM_MAX_CREDIT              (0x7ull << 60)
-#define CA_CRM_MAX_CREDIT_SHFT         60
-       /* bit 63 unused */
-
-/* ==== ca_status1 */
-#define CA_CORELET_ID                  (0x3ull << 0)
-#define CA_CORELET_ID_SHFT             0
-#define CA_INTA_N                      (1ull << 2)
-#define CA_INTB_N                      (1ull << 3)
-#define CA_CRM_CREDIT_AVAIL            (0x7ull << 4)
-#define CA_CRM_CREDIT_AVAIL_SHFT       4
-       /* bit 7 unused */
-#define CA_CRM_SPACE_AVAIL             (0x7full << 8)
-#define CA_CRM_SPACE_AVAIL_SHFT                8
-       /* bit 15 unused */
-#define CA_GART_TLB_VAL                        (0xffull << 16)
-#define CA_GART_TLB_VAL_SHFT           16
-       /* bits 63:24 unused */
-
-/* ==== ca_status2 */
-#define CA_GFX_CREDIT_AVAIL            (0xffull << 0)
-#define CA_GFX_CREDIT_AVAIL_SHFT       0
-#define CA_GFX_OPQ_AVAIL               (0xffull << 8)
-#define CA_GFX_OPQ_AVAIL_SHFT          8
-#define CA_GFX_WRBUFF_AVAIL            (0xffull << 16)
-#define CA_GFX_WRBUFF_AVAIL_SHFT       16
-#define CA_ADMA_OPQ_AVAIL              (0xffull << 24)
-#define CA_ADMA_OPQ_AVAIL_SHFT         24
-#define CA_ADMA_WRBUFF_AVAIL           (0xffull << 32)
-#define CA_ADMA_WRBUFF_AVAIL_SHFT      32
-#define CA_ADMA_RDBUFF_AVAIL           (0x7full << 40)
-#define CA_ADMA_RDBUFF_AVAIL_SHFT      40
-#define CA_PCI_PIO_OP_STAT             (1ull << 47)
-#define CA_PDMA_OPQ_AVAIL              (0xfull << 48)
-#define CA_PDMA_OPQ_AVAIL_SHFT         48
-#define CA_PDMA_WRBUFF_AVAIL           (0xfull << 52)
-#define CA_PDMA_WRBUFF_AVAIL_SHFT      52
-#define CA_PDMA_RDBUFF_AVAIL           (0x3ull << 56)
-#define CA_PDMA_RDBUFF_AVAIL_SHFT      56
-       /* bits 63:58 unused */
-
-/* ==== ca_gart_aperature */
-#define CA_GART_AP_ENB_AGP             (1ull << 0)
-#define CA_GART_PAGE_SIZE              (1ull << 1)
-#define CA_GART_AP_ENB_PCI             (1ull << 2)
-       /* bits 11:3 unused */
-#define CA_GART_AP_SIZE                        (0x3ffull << 12)
-#define CA_GART_AP_SIZE_SHFT           12
-#define CA_GART_AP_BASE                        (0x3ffffffffffull << 22)
-#define CA_GART_AP_BASE_SHFT           22
-
-/* ==== ca_inta_dest_addr
-   ==== ca_intb_dest_addr 
-   ==== ca_err_int_dest_addr */
-       /* bits 2:0 unused */
-#define CA_INT_DEST_ADDR               (0x7ffffffffffffull << 3)
-#define CA_INT_DEST_ADDR_SHFT          3
-       /* bits 55:54 unused */
-#define CA_INT_DEST_VECT               (0xffull << 56)
-#define CA_INT_DEST_VECT_SHFT          56
-
-/* ==== ca_int_status */
-/* ==== ca_int_status_alias */
-/* ==== ca_mult_error */
-/* ==== ca_mult_error_alias */
-/* ==== ca_first_error */
-/* ==== ca_int_mask */
-#define CA_PCI_ERR                     (1ull << 0)
-       /* bits 3:1 unused */
-#define CA_GART_FETCH_ERR              (1ull << 4)
-#define CA_GFX_WR_OVFLW                        (1ull << 5)
-#define CA_PIO_REQ_OVFLW               (1ull << 6)
-#define CA_CRM_PKTERR                  (1ull << 7)
-#define CA_CRM_DVERR                   (1ull << 8)
-#define CA_TNUMTO                      (1ull << 9)
-#define CA_CXM_RSP_CRED_OVFLW          (1ull << 10)
-#define CA_CXM_REQ_CRED_OVFLW          (1ull << 11)
-#define CA_PIO_INVALID_ADDR            (1ull << 12)
-#define CA_PCI_ARB_TO                  (1ull << 13)
-#define CA_AGP_REQ_OFLOW               (1ull << 14)
-#define CA_SBA_TYPE1_ERR               (1ull << 15)
-       /* bit 16 unused */
-#define CA_INTA                                (1ull << 17)
-#define CA_INTB                                (1ull << 18)
-#define CA_MULT_INTA                   (1ull << 19)
-#define CA_MULT_INTB                   (1ull << 20)
-#define CA_GFX_CREDIT_OVFLW            (1ull << 21)
-       /* bits 63:22 unused */
-
-/* ==== ca_crm_pkterr_type */
-/* ==== ca_crm_pkterr_type_alias */
-#define CA_CRM_PKTERR_SBERR_HDR                (1ull << 0)
-#define CA_CRM_PKTERR_DIDN             (1ull << 1)
-#define CA_CRM_PKTERR_PACTYPE          (1ull << 2)
-#define CA_CRM_PKTERR_INV_TNUM         (1ull << 3)
-#define CA_CRM_PKTERR_ADDR_RNG         (1ull << 4)
-#define CA_CRM_PKTERR_ADDR_ALGN                (1ull << 5)
-#define CA_CRM_PKTERR_HDR_PARAM                (1ull << 6)
-#define CA_CRM_PKTERR_CW_ERR           (1ull << 7)
-#define CA_CRM_PKTERR_SBERR_NH         (1ull << 8)
-#define CA_CRM_PKTERR_EARLY_TERM       (1ull << 9)
-#define CA_CRM_PKTERR_EARLY_TAIL       (1ull << 10)
-#define CA_CRM_PKTERR_MSSNG_TAIL       (1ull << 11)
-#define CA_CRM_PKTERR_MSSNG_HDR                (1ull << 12)
-       /* bits 15:13 unused */
-#define CA_FIRST_CRM_PKTERR_SBERR_HDR  (1ull << 16)
-#define CA_FIRST_CRM_PKTERR_DIDN       (1ull << 17)
-#define CA_FIRST_CRM_PKTERR_PACTYPE    (1ull << 18)
-#define CA_FIRST_CRM_PKTERR_INV_TNUM   (1ull << 19)
-#define CA_FIRST_CRM_PKTERR_ADDR_RNG   (1ull << 20)
-#define CA_FIRST_CRM_PKTERR_ADDR_ALGN  (1ull << 21)
-#define CA_FIRST_CRM_PKTERR_HDR_PARAM  (1ull << 22)
-#define CA_FIRST_CRM_PKTERR_CW_ERR     (1ull << 23)
-#define CA_FIRST_CRM_PKTERR_SBERR_NH   (1ull << 24)
-#define CA_FIRST_CRM_PKTERR_EARLY_TERM (1ull << 25)
-#define CA_FIRST_CRM_PKTERR_EARLY_TAIL (1ull << 26)
-#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL (1ull << 27)
-#define CA_FIRST_CRM_PKTERR_MSSNG_HDR  (1ull << 28)
-       /* bits 63:29 unused */
-
-/* ==== ca_crm_ct_error_detail_1 */
-#define CA_PKT_TYPE                    (0xfull << 0)
-#define CA_PKT_TYPE_SHFT               0
-#define CA_SRC_ID                      (0x3ull << 4)
-#define CA_SRC_ID_SHFT                 4
-#define CA_DATA_SZ                     (0x3ull << 6)
-#define CA_DATA_SZ_SHFT                        6
-#define CA_TNUM                                (0xffull << 8)
-#define CA_TNUM_SHFT                   8
-#define CA_DW_DATA_EN                  (0xffull << 16)
-#define CA_DW_DATA_EN_SHFT             16
-#define CA_GFX_CRED                    (0xffull << 24)
-#define CA_GFX_CRED_SHFT               24
-#define CA_MEM_RD_PARAM                        (0x3ull << 32)
-#define CA_MEM_RD_PARAM_SHFT           32
-#define CA_PIO_OP                      (1ull << 34)
-#define CA_CW_ERR                      (1ull << 35)
-       /* bits 62:36 unused */
-#define CA_VALID                       (1ull << 63)
-
-/* ==== ca_crm_ct_error_detail_2 */
-       /* bits 2:0 unused */
-#define CA_PKT_ADDR                    (0x1fffffffffffffull << 3)
-#define CA_PKT_ADDR_SHFT               3
-       /* bits 63:56 unused */
-
-/* ==== ca_crm_tnumto */
-#define CA_CRM_TNUMTO_VAL              (0xffull << 0)
-#define CA_CRM_TNUMTO_VAL_SHFT         0
-#define CA_CRM_TNUMTO_WR               (1ull << 8)
-       /* bits 63:9 unused */
-
-/* ==== ca_gart_err */
-#define CA_GART_ERR_SOURCE             (0x3ull << 0)
-#define CA_GART_ERR_SOURCE_SHFT                0
-       /* bits 3:2 unused */
-#define CA_GART_ERR_ADDR               (0xfffffffffull << 4)
-#define CA_GART_ERR_ADDR_SHFT          4
-       /* bits 63:40 unused */
-
-/* ==== ca_pcierr_type */
-#define CA_PCIERR_DATA                 (0xffffffffull << 0)
-#define CA_PCIERR_DATA_SHFT            0
-#define CA_PCIERR_ENB                  (0xfull << 32)
-#define CA_PCIERR_ENB_SHFT             32
-#define CA_PCIERR_CMD                  (0xfull << 36)
-#define CA_PCIERR_CMD_SHFT             36
-#define CA_PCIERR_A64                  (1ull << 40)
-#define CA_PCIERR_SLV_SERR             (1ull << 41)
-#define CA_PCIERR_SLV_WR_PERR          (1ull << 42)
-#define CA_PCIERR_SLV_RD_PERR          (1ull << 43)
-#define CA_PCIERR_MST_SERR             (1ull << 44)
-#define CA_PCIERR_MST_WR_PERR          (1ull << 45)
-#define CA_PCIERR_MST_RD_PERR          (1ull << 46)
-#define CA_PCIERR_MST_MABT             (1ull << 47)
-#define CA_PCIERR_MST_TABT             (1ull << 48)
-#define CA_PCIERR_MST_RETRY_TOUT       (1ull << 49)
-
-#define CA_PCIERR_TYPES \
-       (CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \
-        CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \
-        CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \
-        CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT)
-
-       /* bits 63:50 unused */
-
-/* ==== ca_pci_dma_addr_extn */
-#define CA_UPPER_NODE_OFFSET           (0x3full << 0)
-#define CA_UPPER_NODE_OFFSET_SHFT      0
-       /* bits 7:6 unused */
-#define CA_CHIPLET_ID                  (0x3ull << 8)
-#define CA_CHIPLET_ID_SHFT             8
-       /* bits 11:10 unused */
-#define CA_PCI_DMA_NODE_ID             (0xffffull << 12)
-#define CA_PCI_DMA_NODE_ID_SHFT                12
-       /* bits 27:26 unused */
-#define CA_PCI_DMA_PIO_MEM_TYPE                (1ull << 28)
-       /* bits 63:29 unused */
-
-
-/* ==== ca_agp_dma_addr_extn */
-       /* bits 19:0 unused */
-#define CA_AGP_DMA_NODE_ID             (0xffffull << 20)
-#define CA_AGP_DMA_NODE_ID_SHFT                20
-       /* bits 27:26 unused */
-#define CA_AGP_DMA_PIO_MEM_TYPE                (1ull << 28)
-       /* bits 63:29 unused */
-
-/* ==== ca_debug_vector_sel */
-#define CA_DEBUG_MN_VSEL               (0xfull << 0)
-#define CA_DEBUG_MN_VSEL_SHFT          0
-#define CA_DEBUG_PP_VSEL               (0xfull << 4)
-#define CA_DEBUG_PP_VSEL_SHFT          4
-#define CA_DEBUG_GW_VSEL               (0xfull << 8)
-#define CA_DEBUG_GW_VSEL_SHFT          8
-#define CA_DEBUG_GT_VSEL               (0xfull << 12)
-#define CA_DEBUG_GT_VSEL_SHFT          12
-#define CA_DEBUG_PD_VSEL               (0xfull << 16)
-#define CA_DEBUG_PD_VSEL_SHFT          16
-#define CA_DEBUG_AD_VSEL               (0xfull << 20)
-#define CA_DEBUG_AD_VSEL_SHFT          20
-#define CA_DEBUG_CX_VSEL               (0xfull << 24)
-#define CA_DEBUG_CX_VSEL_SHFT          24
-#define CA_DEBUG_CR_VSEL               (0xfull << 28)
-#define CA_DEBUG_CR_VSEL_SHFT          28
-#define CA_DEBUG_BA_VSEL               (0xfull << 32)
-#define CA_DEBUG_BA_VSEL_SHFT          32
-#define CA_DEBUG_PE_VSEL               (0xfull << 36)
-#define CA_DEBUG_PE_VSEL_SHFT          36
-#define CA_DEBUG_BO_VSEL               (0xfull << 40)
-#define CA_DEBUG_BO_VSEL_SHFT          40
-#define CA_DEBUG_BI_VSEL               (0xfull << 44)
-#define CA_DEBUG_BI_VSEL_SHFT          44
-#define CA_DEBUG_AS_VSEL               (0xfull << 48)
-#define CA_DEBUG_AS_VSEL_SHFT          48
-#define CA_DEBUG_PS_VSEL               (0xfull << 52)
-#define CA_DEBUG_PS_VSEL_SHFT          52
-#define CA_DEBUG_PM_VSEL               (0xfull << 56)
-#define CA_DEBUG_PM_VSEL_SHFT          56
-       /* bits 63:60 unused */
-
-/* ==== ca_debug_mux_core_sel */
-/* ==== ca_debug_mux_pci_sel */
-#define CA_DEBUG_MSEL0                 (0x7ull << 0)
-#define CA_DEBUG_MSEL0_SHFT            0
-       /* bit 3 unused */
-#define CA_DEBUG_NSEL0                 (0x7ull << 4)
-#define CA_DEBUG_NSEL0_SHFT            4
-       /* bit 7 unused */
-#define CA_DEBUG_MSEL1                 (0x7ull << 8)
-#define CA_DEBUG_MSEL1_SHFT            8
-       /* bit 11 unused */
-#define CA_DEBUG_NSEL1                 (0x7ull << 12)
-#define CA_DEBUG_NSEL1_SHFT            12
-       /* bit 15 unused */
-#define CA_DEBUG_MSEL2                 (0x7ull << 16)
-#define CA_DEBUG_MSEL2_SHFT            16
-       /* bit 19 unused */
-#define CA_DEBUG_NSEL2                 (0x7ull << 20)
-#define CA_DEBUG_NSEL2_SHFT            20
-       /* bit 23 unused */
-#define CA_DEBUG_MSEL3                 (0x7ull << 24)
-#define CA_DEBUG_MSEL3_SHFT            24
-       /* bit 27 unused */
-#define CA_DEBUG_NSEL3                 (0x7ull << 28)
-#define CA_DEBUG_NSEL3_SHFT            28
-       /* bit 31 unused */
-#define CA_DEBUG_MSEL4                 (0x7ull << 32)
-#define CA_DEBUG_MSEL4_SHFT            32
-       /* bit 35 unused */
-#define CA_DEBUG_NSEL4                 (0x7ull << 36)
-#define CA_DEBUG_NSEL4_SHFT            36
-       /* bit 39 unused */
-#define CA_DEBUG_MSEL5                 (0x7ull << 40)
-#define CA_DEBUG_MSEL5_SHFT            40
-       /* bit 43 unused */
-#define CA_DEBUG_NSEL5                 (0x7ull << 44)
-#define CA_DEBUG_NSEL5_SHFT            44
-       /* bit 47 unused */
-#define CA_DEBUG_MSEL6                 (0x7ull << 48)
-#define CA_DEBUG_MSEL6_SHFT            48
-       /* bit 51 unused */
-#define CA_DEBUG_NSEL6                 (0x7ull << 52)
-#define CA_DEBUG_NSEL6_SHFT            52
-       /* bit 55 unused */
-#define CA_DEBUG_MSEL7                 (0x7ull << 56)
-#define CA_DEBUG_MSEL7_SHFT            56
-       /* bit 59 unused */
-#define CA_DEBUG_NSEL7                 (0x7ull << 60)
-#define CA_DEBUG_NSEL7_SHFT            60
-       /* bit 63 unused */
-
-
-/* ==== ca_debug_domain_sel */
-#define CA_DEBUG_DOMAIN_L              (1ull << 0)
-#define CA_DEBUG_DOMAIN_H              (1ull << 1)
-       /* bits 63:2 unused */
-
-/* ==== ca_gart_ptr_table */
-#define CA_GART_PTR_VAL                        (1ull << 0)
-       /* bits 11:1 unused */
-#define CA_GART_PTR_ADDR               (0xfffffffffffull << 12)
-#define CA_GART_PTR_ADDR_SHFT          12
-       /* bits 63:56 unused */
-
-/* ==== ca_gart_tlb_addr[0-7] */
-#define CA_GART_TLB_ADDR               (0xffffffffffffffull << 0)
-#define CA_GART_TLB_ADDR_SHFT          0
-       /* bits 62:56 unused */
-#define CA_GART_TLB_ENTRY_VAL          (1ull << 63)
-
-/*
- * PIO address space ranges for TIO:CA
- */
-
-/* CA internal registers */
-#define CA_PIO_ADMIN                   0x00000000
-#define CA_PIO_ADMIN_LEN               0x00010000
-
-/* GFX Write Buffer - Diagnostics */
-#define CA_PIO_GFX                     0x00010000
-#define CA_PIO_GFX_LEN                 0x00010000
-
-/* AGP DMA Write Buffer - Diagnostics */
-#define CA_PIO_AGP_DMAWRITE            0x00020000
-#define CA_PIO_AGP_DMAWRITE_LEN                0x00010000
-
-/* AGP DMA READ Buffer - Diagnostics */
-#define CA_PIO_AGP_DMAREAD             0x00030000
-#define CA_PIO_AGP_DMAREAD_LEN         0x00010000
-
-/* PCI Config Type 0 */
-#define CA_PIO_PCI_TYPE0_CONFIG                0x01000000
-#define CA_PIO_PCI_TYPE0_CONFIG_LEN    0x01000000
-
-/* PCI Config Type 1 */
-#define CA_PIO_PCI_TYPE1_CONFIG                0x02000000
-#define CA_PIO_PCI_TYPE1_CONFIG_LEN    0x01000000
-
-/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */
-#define CA_PIO_PCI_IO                  0x03000000
-#define CA_PIO_PCI_IO_LEN              0x05000000
-
-/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */
-/*     use Fast Write if enabled and coretalk packet type is a GFX request */
-#define CA_PIO_PCI_MEM_OFFSET          0x08000000
-#define CA_PIO_PCI_MEM_OFFSET_LEN      0x08000000
-
-/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */
-/*     use Fast Write if enabled and coretalk packet type is a GFX request */
-#define CA_PIO_PCI_MEM                 0x40000000
-#define CA_PIO_PCI_MEM_LEN             0xc0000000
-
-/*
- * DMA space
- *
- * The CA aperature (ie. bus address range) mapped by the GART is segmented into
- * two parts.  The lower portion of the aperature is used for mapping 32 bit
- * PCI addresses which are managed by the dma interfaces in this file.  The
- * upper poprtion of the aperature is used for mapping 48 bit AGP addresses.
- * The AGP portion of the aperature is managed by the agpgart_be.c driver
- * in drivers/linux/agp.  There are ca-specific hooks in that driver to
- * manipulate the gart, but management of the AGP portion of the aperature
- * is the responsibility of that driver.
- *
- * CA allows three main types of DMA mapping:
- *
- * PCI 64-bit  Managed by this driver
- * PCI 32-bit  Managed by this driver
- * AGP 48-bit  Managed by hooks in the /dev/agpgart driver
- *
- * All of the above can optionally be remapped through the GART.  The following
- * table lists the combinations of addressing types and GART remapping that
- * is currently supported by the driver (h/w supports all, s/w limits this):
- *
- *             PCI64           PCI32           AGP48
- * GART                no              yes             yes
- * Direct      yes             yes             no
- *
- * GART remapping of PCI64 is not done because there is no need to.  The
- * 64 bit PCI address holds all of the information necessary to target any
- * memory in the system.
- *
- * AGP48 is always mapped through the GART.  Management of the AGP48 portion
- * of the aperature is the responsibility of code in the agpgart_be driver.
- *
- * The non-64 bit bus address space will currently be partitioned like this:
- *
- *     0xffff_ffff_ffff        +--------
- *                             | AGP48 direct
- *                             | Space managed by this driver
- *     CA_AGP_DIRECT_BASE      +--------
- *                             | AGP GART mapped (gfx aperature)
- *                             | Space managed by /dev/agpgart driver
- *                             | This range is exposed to the agpgart
- *                             | driver as the "graphics aperature"
- *     CA_AGP_MAPPED_BASE      +-----
- *                             | PCI GART mapped
- *                             | Space managed by this driver          
- *     CA_PCI32_MAPPED_BASE    +----
- *                             | PCI32 direct
- *                             | Space managed by this driver
- *     0xC000_0000             +--------
- *     (CA_PCI32_DIRECT_BASE)
- *
- * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE
- * is what we call the CA aperature.  Addresses falling in this range will
- * be remapped using the GART.
- *
- * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE
- * is what we call the graphics aperature.  This is a subset of the CA
- * aperature and is under the control of the agpgart_be driver.
- *
- * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are
- * somewhat arbitrary values.  The known constraints on choosing these is:
- *
- * 1)  CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size)
- *     must be one of the values supported by the ca_gart_aperature register.
- *     Currently valid values are: 4MB through 4096MB in powers of 2 increments
- *
- * 2)  CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size)
- *     must be in MB units since that's what the agpgart driver assumes.
- */
-
-/*
- * Define Bus DMA ranges.  These are configurable (see constraints above)
- * and will probably need tuning based on experience.
- */
-
-
-/*
- * 11/24/03
- * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it
- * generally unusable.  The problem is that for PCI direct 32 
- * DMA's, all 32 bits of the bus address are used to form the lower 32 bits
- * of the coretalk address, and coretalk bits 38:32 come from a register.
- * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available
- * for DMA (the rest is allocated to PIO), host node addresses need to be
- * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range
- * as well.  So there can be no PCI32 direct DMA below 3GB!!  For this
- * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes
- * tioca_dma_direct32() a noop but preserves the code flow should this issue
- * be fixed in a respin.
- *
- * For now, all PCI32 DMA's must be mapped through the GART.
- */
-
-#define CA_PCI32_DIRECT_BASE   0xC0000000UL    /* BASE not configurable */
-#define CA_PCI32_DIRECT_SIZE   0x00000000UL    /* 0 MB */
-
-#define CA_PCI32_MAPPED_BASE   0xC0000000UL
-#define CA_PCI32_MAPPED_SIZE   0x40000000UL    /* 2GB */
-
-#define CA_AGP_MAPPED_BASE     0x80000000UL
-#define CA_AGP_MAPPED_SIZE     0x40000000UL    /* 2GB */
-
-#define CA_AGP_DIRECT_BASE     0x40000000UL    /* 2GB */
-#define CA_AGP_DIRECT_SIZE     0x40000000UL
-
-#define CA_APERATURE_BASE      (CA_AGP_MAPPED_BASE)
-#define CA_APERATURE_SIZE      (CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE)
-
-#endif  /* _ASM_IA64_SN_TIO_TIOCA_H */
diff --git a/arch/ia64/include/asm/sn/tioca_provider.h b/arch/ia64/include/asm/sn/tioca_provider.h
deleted file mode 100644 (file)
index 9a820ac..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H
-#define _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H
-
-#include <asm/sn/tioca.h>
-
-/*
- * WAR enables
- * Defines for individual WARs. Each is a bitmask of applicable
- * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B,
- * (3 << 1) == (rev A or rev B), etc
- */
-
-#define TIOCA_WAR_ENABLED(pv, tioca_common) \
-       ((1 << tioca_common->ca_rev) & pv)
-
-  /* TIO:ICE:FRZ:Freezer loses a PIO data ucred on PIO RD RSP with CW error */
-#define PV907908 (1 << 1)
-  /* ATI config space problems after BIOS execution starts */
-#define PV908234 (1 << 1)
-  /* CA:AGPDMA write request data mismatch with ABC1CL merge */
-#define PV895469 (1 << 1)
-  /* TIO:CA TLB invalidate of written GART entries possibly not occurring in CA*/
-#define PV910244 (1 << 1)
-
-struct tioca_dmamap{
-       struct list_head        cad_list;       /* headed by ca_list */
-
-       dma_addr_t              cad_dma_addr;   /* Linux dma handle */
-       uint                    cad_gart_entry; /* start entry in ca_gart_pagemap */
-       uint                    cad_gart_size;  /* #entries for this map */
-};
-
-/*
- * Kernel only fields.  Prom may look at this stuff for debugging only.
- * Access this structure through the ca_kernel_private ptr.
- */
-
-struct tioca_common ;
-
-struct tioca_kernel {
-       struct tioca_common     *ca_common;     /* tioca this belongs to */
-       struct list_head        ca_list;        /* list of all ca's */
-       struct list_head        ca_dmamaps;
-       spinlock_t              ca_lock;        /* Kernel lock */
-       cnodeid_t               ca_closest_node;
-       struct list_head        *ca_devices;    /* bus->devices */
-
-       /*
-        * General GART stuff
-        */
-       u64     ca_ap_size;             /* size of aperature in bytes */
-       u32     ca_gart_entries;        /* # u64 entries in gart */
-       u32     ca_ap_pagesize;         /* aperature page size in bytes */
-       u64     ca_ap_bus_base;         /* bus address of CA aperature */
-       u64     ca_gart_size;           /* gart size in bytes */
-       u64     *ca_gart;               /* gart table vaddr */
-       u64     ca_gart_coretalk_addr;  /* gart coretalk addr */
-       u8              ca_gart_iscoherent;     /* used in tioca_tlbflush */
-
-       /* PCI GART convenience values */
-       u64     ca_pciap_base;          /* pci aperature bus base address */
-       u64     ca_pciap_size;          /* pci aperature size (bytes) */
-       u64     ca_pcigart_base;        /* gfx GART bus base address */
-       u64     *ca_pcigart;            /* gfx GART vm address */
-       u32     ca_pcigart_entries;
-       u32     ca_pcigart_start;       /* PCI start index in ca_gart */
-       void            *ca_pcigart_pagemap;
-
-       /* AGP GART convenience values */
-       u64     ca_gfxap_base;          /* gfx aperature bus base address */
-       u64     ca_gfxap_size;          /* gfx aperature size (bytes) */
-       u64     ca_gfxgart_base;        /* gfx GART bus base address */
-       u64     *ca_gfxgart;            /* gfx GART vm address */
-       u32     ca_gfxgart_entries;
-       u32     ca_gfxgart_start;       /* agpgart start index in ca_gart */
-};
-
-/*
- * Common tioca info shared between kernel and prom
- *
- * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES
- * TO THE PROM VERSION.
- */
-
-struct tioca_common {
-       struct pcibus_bussoft   ca_common;      /* common pciio header */
-
-       u32             ca_rev;
-       u32             ca_closest_nasid;
-
-       u64             ca_prom_private;
-       u64             ca_kernel_private;
-};
-
-/**
- * tioca_paddr_to_gart - Convert an SGI coretalk address to a CA GART entry
- * @paddr: page address to convert
- *
- * Convert a system [coretalk] address to a GART entry.  GART entries are
- * formed using the following:
- *
- *     data = ( (1<<63) |  ( (REMAP_NODE_ID << 40) | (MD_CHIPLET_ID << 38) | 
- * (REMAP_SYS_ADDR) ) >> 12 )
- *
- * DATA written to 1 GART TABLE Entry in system memory is remapped system
- * addr for 1 page 
- *
- * The data is for coretalk address format right shifted 12 bits with a
- * valid bit.
- *
- *     GART_TABLE_ENTRY [ 25:0 ]  -- REMAP_SYS_ADDRESS[37:12].
- *     GART_TABLE_ENTRY [ 27:26 ] -- SHUB MD chiplet id.
- *     GART_TABLE_ENTRY [ 41:28 ] -- REMAP_NODE_ID.
- *     GART_TABLE_ENTRY [ 63 ]    -- Valid Bit 
- */
-static inline u64
-tioca_paddr_to_gart(unsigned long paddr)
-{
-       /*
-        * We are assuming right now that paddr already has the correct
-        * format since the address from xtalk_dmaXXX should already have
-        * NODE_ID, CHIPLET_ID, and SYS_ADDR in the correct locations.
-        */
-
-       return ((paddr) >> 12) | (1UL << 63);
-}
-
-/**
- * tioca_physpage_to_gart - Map a host physical page for SGI CA based DMA
- * @page_addr: system page address to map
- */
-
-static inline unsigned long
-tioca_physpage_to_gart(u64 page_addr)
-{
-       u64 coretalk_addr;
-
-       coretalk_addr = PHYS_TO_TIODMA(page_addr);
-       if (!coretalk_addr) {
-               return 0;
-       }
-
-       return tioca_paddr_to_gart(coretalk_addr);
-}
-
-/**
- * tioca_tlbflush - invalidate cached SGI CA GART TLB entries
- * @tioca_kernel: CA context 
- *
- * Invalidate tlb entries for a given CA GART.  Main complexity is to account
- * for revA bug.
- */
-static inline void
-tioca_tlbflush(struct tioca_kernel *tioca_kernel)
-{
-       volatile u64 tmp;
-       volatile struct tioca __iomem *ca_base;
-       struct tioca_common *tioca_common;
-
-       tioca_common = tioca_kernel->ca_common;
-       ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base;
-
-       /*
-        * Explicit flushes not needed if GART is in cached mode
-        */
-       if (tioca_kernel->ca_gart_iscoherent) {
-               if (TIOCA_WAR_ENABLED(PV910244, tioca_common)) {
-                       /*
-                        * PV910244:  RevA CA needs explicit flushes.
-                        * Need to put GART into uncached mode before
-                        * flushing otherwise the explicit flush is ignored.
-                        *
-                        * Alternate WAR would be to leave GART cached and
-                        * touch every CL aligned GART entry.
-                        */
-
-                       __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM);
-                       __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB);
-                       __sn_setq_relaxed(&ca_base->ca_control2,
-                           (0x2ull << CA_GART_MEM_PARAM_SHFT));
-                       tmp = __sn_readq_relaxed(&ca_base->ca_control2);
-               }
-
-               return;
-       }
-
-       /*
-        * Gart in uncached mode ... need an explicit flush.
-        */
-
-       __sn_setq_relaxed(&ca_base->ca_control2, CA_GART_FLUSH_TLB);
-       tmp = __sn_readq_relaxed(&ca_base->ca_control2);
-}
-
-extern u32     tioca_gart_found;
-extern struct list_head tioca_list;
-extern int tioca_init_provider(void);
-extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern);
-#endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */
diff --git a/arch/ia64/include/asm/sn/tioce.h b/arch/ia64/include/asm/sn/tioce.h
deleted file mode 100644 (file)
index 6eae8ad..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef __ASM_IA64_SN_TIOCE_H__
-#define __ASM_IA64_SN_TIOCE_H__
-
-/* CE ASIC part & mfgr information  */
-#define TIOCE_PART_NUM                 0xCE00
-#define TIOCE_SRC_ID                   0x01
-#define TIOCE_REV_A                    0x1
-
-/* CE Virtual PPB Vendor/Device IDs */
-#define CE_VIRT_PPB_VENDOR_ID          0x10a9
-#define CE_VIRT_PPB_DEVICE_ID          0x4002
-
-/* CE Host Bridge Vendor/Device IDs */
-#define CE_HOST_BRIDGE_VENDOR_ID       0x10a9
-#define CE_HOST_BRIDGE_DEVICE_ID       0x4001
-
-
-#define TIOCE_NUM_M40_ATES             4096
-#define TIOCE_NUM_M3240_ATES           2048
-#define TIOCE_NUM_PORTS                        2
-
-/*
- * Register layout for TIOCE.  MMR offsets are shown at the far right of the
- * structure definition.
- */
-typedef volatile struct tioce {
-       /*
-        * ADMIN : Administration Registers
-        */
-       u64     ce_adm_id;                              /* 0x000000 */
-       u64     ce_pad_000008;                          /* 0x000008 */
-       u64     ce_adm_dyn_credit_status;               /* 0x000010 */
-       u64     ce_adm_last_credit_status;              /* 0x000018 */
-       u64     ce_adm_credit_limit;                    /* 0x000020 */
-       u64     ce_adm_force_credit;                    /* 0x000028 */
-       u64     ce_adm_control;                         /* 0x000030 */
-       u64     ce_adm_mmr_chn_timeout;                 /* 0x000038 */
-       u64     ce_adm_ssp_ure_timeout;                 /* 0x000040 */
-       u64     ce_adm_ssp_dre_timeout;                 /* 0x000048 */
-       u64     ce_adm_ssp_debug_sel;                   /* 0x000050 */
-       u64     ce_adm_int_status;                      /* 0x000058 */
-       u64     ce_adm_int_status_alias;                /* 0x000060 */
-       u64     ce_adm_int_mask;                        /* 0x000068 */
-       u64     ce_adm_int_pending;                     /* 0x000070 */
-       u64     ce_adm_force_int;                       /* 0x000078 */
-       u64     ce_adm_ure_ups_buf_barrier_flush;       /* 0x000080 */
-       u64     ce_adm_int_dest[15];        /* 0x000088 -- 0x0000F8 */
-       u64     ce_adm_error_summary;                   /* 0x000100 */
-       u64     ce_adm_error_summary_alias;             /* 0x000108 */
-       u64     ce_adm_error_mask;                      /* 0x000110 */
-       u64     ce_adm_first_error;                     /* 0x000118 */
-       u64     ce_adm_error_overflow;                  /* 0x000120 */
-       u64     ce_adm_error_overflow_alias;            /* 0x000128 */
-       u64     ce_pad_000130[2];           /* 0x000130 -- 0x000138 */
-       u64     ce_adm_tnum_error;                      /* 0x000140 */
-       u64     ce_adm_mmr_err_detail;                  /* 0x000148 */
-       u64     ce_adm_msg_sram_perr_detail;            /* 0x000150 */
-       u64     ce_adm_bap_sram_perr_detail;            /* 0x000158 */
-       u64     ce_adm_ce_sram_perr_detail;             /* 0x000160 */
-       u64     ce_adm_ce_credit_oflow_detail;          /* 0x000168 */
-       u64     ce_adm_tx_link_idle_max_timer;          /* 0x000170 */
-       u64     ce_adm_pcie_debug_sel;                  /* 0x000178 */
-       u64     ce_pad_000180[16];          /* 0x000180 -- 0x0001F8 */
-
-       u64     ce_adm_pcie_debug_sel_top;              /* 0x000200 */
-       u64     ce_adm_pcie_debug_lat_sel_lo_top;       /* 0x000208 */
-       u64     ce_adm_pcie_debug_lat_sel_hi_top;       /* 0x000210 */
-       u64     ce_adm_pcie_debug_trig_sel_top;         /* 0x000218 */
-       u64     ce_adm_pcie_debug_trig_lat_sel_lo_top;  /* 0x000220 */
-       u64     ce_adm_pcie_debug_trig_lat_sel_hi_top;  /* 0x000228 */
-       u64     ce_adm_pcie_trig_compare_top;           /* 0x000230 */
-       u64     ce_adm_pcie_trig_compare_en_top;        /* 0x000238 */
-       u64     ce_adm_ssp_debug_sel_top;               /* 0x000240 */
-       u64     ce_adm_ssp_debug_lat_sel_lo_top;        /* 0x000248 */
-       u64     ce_adm_ssp_debug_lat_sel_hi_top;        /* 0x000250 */
-       u64     ce_adm_ssp_debug_trig_sel_top;          /* 0x000258 */
-       u64     ce_adm_ssp_debug_trig_lat_sel_lo_top;   /* 0x000260 */
-       u64     ce_adm_ssp_debug_trig_lat_sel_hi_top;   /* 0x000268 */
-       u64     ce_adm_ssp_trig_compare_top;            /* 0x000270 */
-       u64     ce_adm_ssp_trig_compare_en_top;         /* 0x000278 */
-       u64     ce_pad_000280[48];          /* 0x000280 -- 0x0003F8 */
-
-       u64     ce_adm_bap_ctrl;                        /* 0x000400 */
-       u64     ce_pad_000408[127];         /* 0x000408 -- 0x0007F8 */
-
-       u64     ce_msg_buf_data63_0[35];    /* 0x000800 -- 0x000918 */
-       u64     ce_pad_000920[29];          /* 0x000920 -- 0x0009F8 */
-
-       u64     ce_msg_buf_data127_64[35];  /* 0x000A00 -- 0x000B18 */
-       u64     ce_pad_000B20[29];          /* 0x000B20 -- 0x000BF8 */
-
-       u64     ce_msg_buf_parity[35];      /* 0x000C00 -- 0x000D18 */
-       u64     ce_pad_000D20[29];          /* 0x000D20 -- 0x000DF8 */
-
-       u64     ce_pad_000E00[576];         /* 0x000E00 -- 0x001FF8 */
-
-       /*
-        * LSI : LSI's PCI Express Link Registers (Link#1 and Link#2)
-        * Link#1 MMRs at start at 0x002000, Link#2 MMRs at 0x003000
-        * NOTE: the comment offsets at far right: let 'z' = {2 or 3}
-        */
-       #define ce_lsi(link_num)        ce_lsi[link_num-1]
-       struct ce_lsi_reg {
-               u64     ce_lsi_lpu_id;                  /* 0x00z000 */
-               u64     ce_lsi_rst;                     /* 0x00z008 */
-               u64     ce_lsi_dbg_stat;                /* 0x00z010 */
-               u64     ce_lsi_dbg_cfg;                 /* 0x00z018 */
-               u64     ce_lsi_ltssm_ctrl;              /* 0x00z020 */
-               u64     ce_lsi_lk_stat;                 /* 0x00z028 */
-               u64     ce_pad_00z030[2];   /* 0x00z030 -- 0x00z038 */
-               u64     ce_lsi_int_and_stat;            /* 0x00z040 */
-               u64     ce_lsi_int_mask;                /* 0x00z048 */
-               u64     ce_pad_00z050[22];  /* 0x00z050 -- 0x00z0F8 */
-               u64     ce_lsi_lk_perf_cnt_sel;         /* 0x00z100 */
-               u64     ce_pad_00z108;                  /* 0x00z108 */
-               u64     ce_lsi_lk_perf_cnt_ctrl;        /* 0x00z110 */
-               u64     ce_pad_00z118;                  /* 0x00z118 */
-               u64     ce_lsi_lk_perf_cnt1;            /* 0x00z120 */
-               u64     ce_lsi_lk_perf_cnt1_test;       /* 0x00z128 */
-               u64     ce_lsi_lk_perf_cnt2;            /* 0x00z130 */
-               u64     ce_lsi_lk_perf_cnt2_test;       /* 0x00z138 */
-               u64     ce_pad_00z140[24];  /* 0x00z140 -- 0x00z1F8 */
-               u64     ce_lsi_lk_lyr_cfg;              /* 0x00z200 */
-               u64     ce_lsi_lk_lyr_status;           /* 0x00z208 */
-               u64     ce_lsi_lk_lyr_int_stat;         /* 0x00z210 */
-               u64     ce_lsi_lk_ly_int_stat_test;     /* 0x00z218 */
-               u64     ce_lsi_lk_ly_int_stat_mask;     /* 0x00z220 */
-               u64     ce_pad_00z228[3];   /* 0x00z228 -- 0x00z238 */
-               u64     ce_lsi_fc_upd_ctl;              /* 0x00z240 */
-               u64     ce_pad_00z248[3];   /* 0x00z248 -- 0x00z258 */
-               u64     ce_lsi_flw_ctl_upd_to_timer;    /* 0x00z260 */
-               u64     ce_lsi_flw_ctl_upd_timer0;      /* 0x00z268 */
-               u64     ce_lsi_flw_ctl_upd_timer1;      /* 0x00z270 */
-               u64     ce_pad_00z278[49];  /* 0x00z278 -- 0x00z3F8 */
-               u64     ce_lsi_freq_nak_lat_thrsh;      /* 0x00z400 */
-               u64     ce_lsi_ack_nak_lat_tmr;         /* 0x00z408 */
-               u64     ce_lsi_rply_tmr_thr;            /* 0x00z410 */
-               u64     ce_lsi_rply_tmr;                /* 0x00z418 */
-               u64     ce_lsi_rply_num_stat;           /* 0x00z420 */
-               u64     ce_lsi_rty_buf_max_addr;        /* 0x00z428 */
-               u64     ce_lsi_rty_fifo_ptr;            /* 0x00z430 */
-               u64     ce_lsi_rty_fifo_rd_wr_ptr;      /* 0x00z438 */
-               u64     ce_lsi_rty_fifo_cred;           /* 0x00z440 */
-               u64     ce_lsi_seq_cnt;                 /* 0x00z448 */
-               u64     ce_lsi_ack_sent_seq_num;        /* 0x00z450 */
-               u64     ce_lsi_seq_cnt_fifo_max_addr;   /* 0x00z458 */
-               u64     ce_lsi_seq_cnt_fifo_ptr;        /* 0x00z460 */
-               u64     ce_lsi_seq_cnt_rd_wr_ptr;       /* 0x00z468 */
-               u64     ce_lsi_tx_lk_ts_ctl;            /* 0x00z470 */
-               u64     ce_pad_00z478;                  /* 0x00z478 */
-               u64     ce_lsi_mem_addr_ctl;            /* 0x00z480 */
-               u64     ce_lsi_mem_d_ld0;               /* 0x00z488 */
-               u64     ce_lsi_mem_d_ld1;               /* 0x00z490 */
-               u64     ce_lsi_mem_d_ld2;               /* 0x00z498 */
-               u64     ce_lsi_mem_d_ld3;               /* 0x00z4A0 */
-               u64     ce_lsi_mem_d_ld4;               /* 0x00z4A8 */
-               u64     ce_pad_00z4B0[2];   /* 0x00z4B0 -- 0x00z4B8 */
-               u64     ce_lsi_rty_d_cnt;               /* 0x00z4C0 */
-               u64     ce_lsi_seq_buf_cnt;             /* 0x00z4C8 */
-               u64     ce_lsi_seq_buf_bt_d;            /* 0x00z4D0 */
-               u64     ce_pad_00z4D8;                  /* 0x00z4D8 */
-               u64     ce_lsi_ack_lat_thr;             /* 0x00z4E0 */
-               u64     ce_pad_00z4E8[3];   /* 0x00z4E8 -- 0x00z4F8 */
-               u64     ce_lsi_nxt_rcv_seq_1_cntr;      /* 0x00z500 */
-               u64     ce_lsi_unsp_dllp_rcvd;          /* 0x00z508 */
-               u64     ce_lsi_rcv_lk_ts_ctl;           /* 0x00z510 */
-               u64     ce_pad_00z518[29];  /* 0x00z518 -- 0x00z5F8 */
-               u64     ce_lsi_phy_lyr_cfg;             /* 0x00z600 */
-               u64     ce_pad_00z608;                  /* 0x00z608 */
-               u64     ce_lsi_phy_lyr_int_stat;        /* 0x00z610 */
-               u64     ce_lsi_phy_lyr_int_stat_test;   /* 0x00z618 */
-               u64     ce_lsi_phy_lyr_int_mask;        /* 0x00z620 */
-               u64     ce_pad_00z628[11];  /* 0x00z628 -- 0x00z678 */
-               u64     ce_lsi_rcv_phy_cfg;             /* 0x00z680 */
-               u64     ce_lsi_rcv_phy_stat1;           /* 0x00z688 */
-               u64     ce_lsi_rcv_phy_stat2;           /* 0x00z690 */
-               u64     ce_lsi_rcv_phy_stat3;           /* 0x00z698 */
-               u64     ce_lsi_rcv_phy_int_stat;        /* 0x00z6A0 */
-               u64     ce_lsi_rcv_phy_int_stat_test;   /* 0x00z6A8 */
-               u64     ce_lsi_rcv_phy_int_mask;        /* 0x00z6B0 */
-               u64     ce_pad_00z6B8[9];   /* 0x00z6B8 -- 0x00z6F8 */
-               u64     ce_lsi_tx_phy_cfg;              /* 0x00z700 */
-               u64     ce_lsi_tx_phy_stat;             /* 0x00z708 */
-               u64     ce_lsi_tx_phy_int_stat;         /* 0x00z710 */
-               u64     ce_lsi_tx_phy_int_stat_test;    /* 0x00z718 */
-               u64     ce_lsi_tx_phy_int_mask;         /* 0x00z720 */
-               u64     ce_lsi_tx_phy_stat2;            /* 0x00z728 */
-               u64     ce_pad_00z730[10];  /* 0x00z730 -- 0x00z77F */
-               u64     ce_lsi_ltssm_cfg1;              /* 0x00z780 */
-               u64     ce_lsi_ltssm_cfg2;              /* 0x00z788 */
-               u64     ce_lsi_ltssm_cfg3;              /* 0x00z790 */
-               u64     ce_lsi_ltssm_cfg4;              /* 0x00z798 */
-               u64     ce_lsi_ltssm_cfg5;              /* 0x00z7A0 */
-               u64     ce_lsi_ltssm_stat1;             /* 0x00z7A8 */
-               u64     ce_lsi_ltssm_stat2;             /* 0x00z7B0 */
-               u64     ce_lsi_ltssm_int_stat;          /* 0x00z7B8 */
-               u64     ce_lsi_ltssm_int_stat_test;     /* 0x00z7C0 */
-               u64     ce_lsi_ltssm_int_mask;          /* 0x00z7C8 */
-               u64     ce_lsi_ltssm_stat_wr_en;        /* 0x00z7D0 */
-               u64     ce_pad_00z7D8[5];   /* 0x00z7D8 -- 0x00z7F8 */
-               u64     ce_lsi_gb_cfg1;                 /* 0x00z800 */
-               u64     ce_lsi_gb_cfg2;                 /* 0x00z808 */
-               u64     ce_lsi_gb_cfg3;                 /* 0x00z810 */
-               u64     ce_lsi_gb_cfg4;                 /* 0x00z818 */
-               u64     ce_lsi_gb_stat;                 /* 0x00z820 */
-               u64     ce_lsi_gb_int_stat;             /* 0x00z828 */
-               u64     ce_lsi_gb_int_stat_test;        /* 0x00z830 */
-               u64     ce_lsi_gb_int_mask;             /* 0x00z838 */
-               u64     ce_lsi_gb_pwr_dn1;              /* 0x00z840 */
-               u64     ce_lsi_gb_pwr_dn2;              /* 0x00z848 */
-               u64     ce_pad_00z850[246]; /* 0x00z850 -- 0x00zFF8 */
-       } ce_lsi[2];
-
-       u64     ce_pad_004000[10];          /* 0x004000 -- 0x004048 */
-
-       /*
-        * CRM: Coretalk Receive Module Registers
-        */
-       u64     ce_crm_debug_mux;                       /* 0x004050 */
-       u64     ce_pad_004058;                          /* 0x004058 */
-       u64     ce_crm_ssp_err_cmd_wrd;                 /* 0x004060 */
-       u64     ce_crm_ssp_err_addr;                    /* 0x004068 */
-       u64     ce_crm_ssp_err_syn;                     /* 0x004070 */
-
-       u64     ce_pad_004078[499];         /* 0x004078 -- 0x005008 */
-
-       /*
-         * CXM: Coretalk Xmit Module Registers
-         */
-       u64     ce_cxm_dyn_credit_status;               /* 0x005010 */
-       u64     ce_cxm_last_credit_status;              /* 0x005018 */
-       u64     ce_cxm_credit_limit;                    /* 0x005020 */
-       u64     ce_cxm_force_credit;                    /* 0x005028 */
-       u64     ce_cxm_disable_bypass;                  /* 0x005030 */
-       u64     ce_pad_005038[3];           /* 0x005038 -- 0x005048 */
-       u64     ce_cxm_debug_mux;                       /* 0x005050 */
-
-        u64        ce_pad_005058[501];         /* 0x005058 -- 0x005FF8 */
-
-       /*
-        * DTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
-        * DTL: Link#1 MMRs at start at 0x006000, Link#2 MMRs at 0x008000
-        * DTL: the comment offsets at far right: let 'y' = {6 or 8}
-        *
-        * UTL: Downstream Transaction Layer Regs (Link#1 and Link#2)
-        * UTL: Link#1 MMRs at start at 0x007000, Link#2 MMRs at 0x009000
-        * UTL: the comment offsets at far right: let 'z' = {7 or 9}
-        */
-       #define ce_dtl(link_num)        ce_dtl_utl[link_num-1]
-       #define ce_utl(link_num)        ce_dtl_utl[link_num-1]
-       struct ce_dtl_utl_reg {
-               /* DTL */
-               u64     ce_dtl_dtdr_credit_limit;       /* 0x00y000 */
-               u64     ce_dtl_dtdr_credit_force;       /* 0x00y008 */
-               u64     ce_dtl_dyn_credit_status;       /* 0x00y010 */
-               u64     ce_dtl_dtl_last_credit_stat;    /* 0x00y018 */
-               u64     ce_dtl_dtl_ctrl;                /* 0x00y020 */
-               u64     ce_pad_00y028[5];   /* 0x00y028 -- 0x00y048 */
-               u64     ce_dtl_debug_sel;               /* 0x00y050 */
-               u64     ce_pad_00y058[501]; /* 0x00y058 -- 0x00yFF8 */
-
-               /* UTL */
-               u64     ce_utl_utl_ctrl;                /* 0x00z000 */
-               u64     ce_utl_debug_sel;               /* 0x00z008 */
-               u64     ce_pad_00z010[510]; /* 0x00z010 -- 0x00zFF8 */
-       } ce_dtl_utl[2];
-
-       u64     ce_pad_00A000[514];         /* 0x00A000 -- 0x00B008 */
-
-       /*
-        * URE: Upstream Request Engine
-         */
-       u64     ce_ure_dyn_credit_status;               /* 0x00B010 */
-       u64     ce_ure_last_credit_status;              /* 0x00B018 */
-       u64     ce_ure_credit_limit;                    /* 0x00B020 */
-       u64     ce_pad_00B028;                          /* 0x00B028 */
-       u64     ce_ure_control;                         /* 0x00B030 */
-       u64     ce_ure_status;                          /* 0x00B038 */
-       u64     ce_pad_00B040[2];           /* 0x00B040 -- 0x00B048 */
-       u64     ce_ure_debug_sel;                       /* 0x00B050 */
-       u64     ce_ure_pcie_debug_sel;                  /* 0x00B058 */
-       u64     ce_ure_ssp_err_cmd_wrd;                 /* 0x00B060 */
-       u64     ce_ure_ssp_err_addr;                    /* 0x00B068 */
-       u64     ce_ure_page_map;                        /* 0x00B070 */
-       u64     ce_ure_dir_map[TIOCE_NUM_PORTS];        /* 0x00B078 */
-       u64     ce_ure_pipe_sel1;                       /* 0x00B088 */
-       u64     ce_ure_pipe_mask1;                      /* 0x00B090 */
-       u64     ce_ure_pipe_sel2;                       /* 0x00B098 */
-       u64     ce_ure_pipe_mask2;                      /* 0x00B0A0 */
-       u64     ce_ure_pcie1_credits_sent;              /* 0x00B0A8 */
-       u64     ce_ure_pcie1_credits_used;              /* 0x00B0B0 */
-       u64     ce_ure_pcie1_credit_limit;              /* 0x00B0B8 */
-       u64     ce_ure_pcie2_credits_sent;              /* 0x00B0C0 */
-       u64     ce_ure_pcie2_credits_used;              /* 0x00B0C8 */
-       u64     ce_ure_pcie2_credit_limit;              /* 0x00B0D0 */
-       u64     ce_ure_pcie_force_credit;               /* 0x00B0D8 */
-       u64     ce_ure_rd_tnum_val;                     /* 0x00B0E0 */
-       u64     ce_ure_rd_tnum_rsp_rcvd;                /* 0x00B0E8 */
-       u64     ce_ure_rd_tnum_esent_timer;             /* 0x00B0F0 */
-       u64     ce_ure_rd_tnum_error;                   /* 0x00B0F8 */
-       u64     ce_ure_rd_tnum_first_cl;                /* 0x00B100 */
-       u64     ce_ure_rd_tnum_link_buf;                /* 0x00B108 */
-       u64     ce_ure_wr_tnum_val;                     /* 0x00B110 */
-       u64     ce_ure_sram_err_addr0;                  /* 0x00B118 */
-       u64     ce_ure_sram_err_addr1;                  /* 0x00B120 */
-       u64     ce_ure_sram_err_addr2;                  /* 0x00B128 */
-       u64     ce_ure_sram_rd_addr0;                   /* 0x00B130 */
-       u64     ce_ure_sram_rd_addr1;                   /* 0x00B138 */
-       u64     ce_ure_sram_rd_addr2;                   /* 0x00B140 */
-       u64     ce_ure_sram_wr_addr0;                   /* 0x00B148 */
-       u64     ce_ure_sram_wr_addr1;                   /* 0x00B150 */
-       u64     ce_ure_sram_wr_addr2;                   /* 0x00B158 */
-       u64     ce_ure_buf_flush10;                     /* 0x00B160 */
-       u64     ce_ure_buf_flush11;                     /* 0x00B168 */
-       u64     ce_ure_buf_flush12;                     /* 0x00B170 */
-       u64     ce_ure_buf_flush13;                     /* 0x00B178 */
-       u64     ce_ure_buf_flush20;                     /* 0x00B180 */
-       u64     ce_ure_buf_flush21;                     /* 0x00B188 */
-       u64     ce_ure_buf_flush22;                     /* 0x00B190 */
-       u64     ce_ure_buf_flush23;                     /* 0x00B198 */
-       u64     ce_ure_pcie_control1;                   /* 0x00B1A0 */
-       u64     ce_ure_pcie_control2;                   /* 0x00B1A8 */
-
-       u64     ce_pad_00B1B0[458];         /* 0x00B1B0 -- 0x00BFF8 */
-
-       /* Upstream Data Buffer, Port1 */
-       struct ce_ure_maint_ups_dat1_data {
-               u64     data63_0[512];      /* 0x00C000 -- 0x00CFF8 */
-               u64     data127_64[512];    /* 0x00D000 -- 0x00DFF8 */
-               u64     parity[512];        /* 0x00E000 -- 0x00EFF8 */
-       } ce_ure_maint_ups_dat1;
-
-       /* Upstream Header Buffer, Port1 */
-       struct ce_ure_maint_ups_hdr1_data {
-               u64     data63_0[512];      /* 0x00F000 -- 0x00FFF8 */
-               u64     data127_64[512];    /* 0x010000 -- 0x010FF8 */
-               u64     parity[512];        /* 0x011000 -- 0x011FF8 */
-       } ce_ure_maint_ups_hdr1;
-
-       /* Upstream Data Buffer, Port2 */
-       struct ce_ure_maint_ups_dat2_data {
-               u64     data63_0[512];      /* 0x012000 -- 0x012FF8 */
-               u64     data127_64[512];    /* 0x013000 -- 0x013FF8 */
-               u64     parity[512];        /* 0x014000 -- 0x014FF8 */
-       } ce_ure_maint_ups_dat2;
-
-       /* Upstream Header Buffer, Port2 */
-       struct ce_ure_maint_ups_hdr2_data {
-               u64     data63_0[512];      /* 0x015000 -- 0x015FF8 */
-               u64     data127_64[512];    /* 0x016000 -- 0x016FF8 */
-               u64     parity[512];        /* 0x017000 -- 0x017FF8 */
-       } ce_ure_maint_ups_hdr2;
-
-       /* Downstream Data Buffer */
-       struct ce_ure_maint_dns_dat_data {
-               u64     data63_0[512];      /* 0x018000 -- 0x018FF8 */
-               u64     data127_64[512];    /* 0x019000 -- 0x019FF8 */
-               u64     parity[512];        /* 0x01A000 -- 0x01AFF8 */
-       } ce_ure_maint_dns_dat;
-
-       /* Downstream Header Buffer */
-       struct  ce_ure_maint_dns_hdr_data {
-               u64     data31_0[64];       /* 0x01B000 -- 0x01B1F8 */
-               u64     data95_32[64];      /* 0x01B200 -- 0x01B3F8 */
-               u64     parity[64];         /* 0x01B400 -- 0x01B5F8 */
-       } ce_ure_maint_dns_hdr;
-
-       /* RCI Buffer Data */
-       struct  ce_ure_maint_rci_data {
-               u64     data41_0[64];       /* 0x01B600 -- 0x01B7F8 */
-               u64     data69_42[64];      /* 0x01B800 -- 0x01B9F8 */
-       } ce_ure_maint_rci;
-
-       /* Response Queue */
-       u64     ce_ure_maint_rspq[64];      /* 0x01BA00 -- 0x01BBF8 */
-
-       u64     ce_pad_01C000[4224];        /* 0x01BC00 -- 0x023FF8 */
-
-       /* Admin Build-a-Packet Buffer */
-       struct  ce_adm_maint_bap_buf_data {
-               u64     data63_0[258];      /* 0x024000 -- 0x024808 */
-               u64     data127_64[258];    /* 0x024810 -- 0x025018 */
-               u64     parity[258];        /* 0x025020 -- 0x025828 */
-       } ce_adm_maint_bap_buf;
-
-       u64     ce_pad_025830[5370];        /* 0x025830 -- 0x02FFF8 */
-
-       /* URE: 40bit PMU ATE Buffer */             /* 0x030000 -- 0x037FF8 */
-       u64     ce_ure_ate40[TIOCE_NUM_M40_ATES];
-
-       /* URE: 32/40bit PMU ATE Buffer */          /* 0x038000 -- 0x03BFF8 */
-       u64     ce_ure_ate3240[TIOCE_NUM_M3240_ATES];
-
-       u64     ce_pad_03C000[2050];        /* 0x03C000 -- 0x040008 */
-
-       /*
-        * DRE: Down Stream Request Engine
-         */
-       u64     ce_dre_dyn_credit_status1;              /* 0x040010 */
-       u64     ce_dre_dyn_credit_status2;              /* 0x040018 */
-       u64     ce_dre_last_credit_status1;             /* 0x040020 */
-       u64     ce_dre_last_credit_status2;             /* 0x040028 */
-       u64     ce_dre_credit_limit1;                   /* 0x040030 */
-       u64     ce_dre_credit_limit2;                   /* 0x040038 */
-       u64     ce_dre_force_credit1;                   /* 0x040040 */
-       u64     ce_dre_force_credit2;                   /* 0x040048 */
-       u64     ce_dre_debug_mux1;                      /* 0x040050 */
-       u64     ce_dre_debug_mux2;                      /* 0x040058 */
-       u64     ce_dre_ssp_err_cmd_wrd;                 /* 0x040060 */
-       u64     ce_dre_ssp_err_addr;                    /* 0x040068 */
-       u64     ce_dre_comp_err_cmd_wrd;                /* 0x040070 */
-       u64     ce_dre_comp_err_addr;                   /* 0x040078 */
-       u64     ce_dre_req_status;                      /* 0x040080 */
-       u64     ce_dre_config1;                         /* 0x040088 */
-       u64     ce_dre_config2;                         /* 0x040090 */
-       u64     ce_dre_config_req_status;               /* 0x040098 */
-       u64     ce_pad_0400A0[12];          /* 0x0400A0 -- 0x0400F8 */
-       u64     ce_dre_dyn_fifo;                        /* 0x040100 */
-       u64     ce_pad_040108[3];           /* 0x040108 -- 0x040118 */
-       u64     ce_dre_last_fifo;                       /* 0x040120 */
-
-       u64     ce_pad_040128[27];          /* 0x040128 -- 0x0401F8 */
-
-       /* DRE Downstream Head Queue */
-       struct  ce_dre_maint_ds_head_queue {
-               u64     data63_0[32];       /* 0x040200 -- 0x0402F8 */
-               u64     data127_64[32];     /* 0x040300 -- 0x0403F8 */
-               u64     parity[32];         /* 0x040400 -- 0x0404F8 */
-       } ce_dre_maint_ds_head_q;
-
-       u64     ce_pad_040500[352];         /* 0x040500 -- 0x040FF8 */
-
-       /* DRE Downstream Data Queue */
-       struct  ce_dre_maint_ds_data_queue {
-               u64     data63_0[256];      /* 0x041000 -- 0x0417F8 */
-               u64     ce_pad_041800[256]; /* 0x041800 -- 0x041FF8 */
-               u64     data127_64[256];    /* 0x042000 -- 0x0427F8 */
-               u64     ce_pad_042800[256]; /* 0x042800 -- 0x042FF8 */
-               u64     parity[256];        /* 0x043000 -- 0x0437F8 */
-               u64     ce_pad_043800[256]; /* 0x043800 -- 0x043FF8 */
-       } ce_dre_maint_ds_data_q;
-
-       /* DRE URE Upstream Response Queue */
-       struct  ce_dre_maint_ure_us_rsp_queue {
-               u64     data63_0[8];        /* 0x044000 -- 0x044038 */
-               u64     ce_pad_044040[24];  /* 0x044040 -- 0x0440F8 */
-               u64     data127_64[8];      /* 0x044100 -- 0x044138 */
-               u64     ce_pad_044140[24];  /* 0x044140 -- 0x0441F8 */
-               u64     parity[8];          /* 0x044200 -- 0x044238 */
-               u64     ce_pad_044240[24];  /* 0x044240 -- 0x0442F8 */
-       } ce_dre_maint_ure_us_rsp_q;
-
-       u64     ce_dre_maint_us_wrt_rsp[32];/* 0x044300 -- 0x0443F8 */
-
-       u64     ce_end_of_struct;                       /* 0x044400 */
-} tioce_t;
-
-/* ce_lsiX_gb_cfg1 register bit masks & shifts */
-#define CE_LSI_GB_CFG1_RXL0S_THS_SHFT  0
-#define CE_LSI_GB_CFG1_RXL0S_THS_MASK  (0xffULL << 0)
-#define CE_LSI_GB_CFG1_RXL0S_SMP_SHFT  8
-#define CE_LSI_GB_CFG1_RXL0S_SMP_MASK  (0xfULL << 8)
-#define CE_LSI_GB_CFG1_RXL0S_ADJ_SHFT  12
-#define CE_LSI_GB_CFG1_RXL0S_ADJ_MASK  (0x7ULL << 12)
-#define CE_LSI_GB_CFG1_RXL0S_FLT_SHFT  15
-#define CE_LSI_GB_CFG1_RXL0S_FLT_MASK  (0x1ULL << 15)
-#define CE_LSI_GB_CFG1_LPBK_SEL_SHFT   16
-#define CE_LSI_GB_CFG1_LPBK_SEL_MASK   (0x3ULL << 16)
-#define CE_LSI_GB_CFG1_LPBK_EN_SHFT    18
-#define CE_LSI_GB_CFG1_LPBK_EN_MASK    (0x1ULL << 18)
-#define CE_LSI_GB_CFG1_RVRS_LB_SHFT    19
-#define CE_LSI_GB_CFG1_RVRS_LB_MASK    (0x1ULL << 19)
-#define CE_LSI_GB_CFG1_RVRS_CLK_SHFT   20
-#define CE_LSI_GB_CFG1_RVRS_CLK_MASK   (0x3ULL << 20)
-#define CE_LSI_GB_CFG1_SLF_TS_SHFT     24
-#define CE_LSI_GB_CFG1_SLF_TS_MASK     (0xfULL << 24)
-
-/* ce_adm_int_mask/ce_adm_int_status register bit defines */
-#define CE_ADM_INT_CE_ERROR_SHFT               0
-#define CE_ADM_INT_LSI1_IP_ERROR_SHFT          1
-#define CE_ADM_INT_LSI2_IP_ERROR_SHFT          2
-#define CE_ADM_INT_PCIE_ERROR_SHFT             3
-#define CE_ADM_INT_PORT1_HOTPLUG_EVENT_SHFT    4
-#define CE_ADM_INT_PORT2_HOTPLUG_EVENT_SHFT    5
-#define CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT       6
-#define CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT       7
-#define CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT       8
-#define CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT       9
-#define CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT       10
-#define CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT       11
-#define CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT       12
-#define CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT       13
-#define CE_ADM_INT_PCIE_MSG_SHFT               14 /*see int_dest_14*/
-#define CE_ADM_INT_PCIE_MSG_SLOT_0_SHFT                14
-#define CE_ADM_INT_PCIE_MSG_SLOT_1_SHFT                15
-#define CE_ADM_INT_PCIE_MSG_SLOT_2_SHFT                16
-#define CE_ADM_INT_PCIE_MSG_SLOT_3_SHFT                17
-#define CE_ADM_INT_PORT1_PM_PME_MSG_SHFT       22
-#define CE_ADM_INT_PORT2_PM_PME_MSG_SHFT       23
-
-/* ce_adm_force_int register bit defines */
-#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT 0
-#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT 1
-#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT 2
-#define CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT 3
-#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT 4
-#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT 5
-#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT 6
-#define CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT 7
-#define CE_ADM_FORCE_INT_ALWAYS_SHFT           8
-
-/* ce_adm_int_dest register bit masks & shifts */
-#define INTR_VECTOR_SHFT                       56
-
-/* ce_adm_error_mask and ce_adm_error_summary register bit masks */
-#define CE_ADM_ERR_CRM_SSP_REQ_INVALID                 (0x1ULL <<  0)
-#define CE_ADM_ERR_SSP_REQ_HEADER                      (0x1ULL <<  1)
-#define CE_ADM_ERR_SSP_RSP_HEADER                      (0x1ULL <<  2)
-#define CE_ADM_ERR_SSP_PROTOCOL_ERROR                  (0x1ULL <<  3)
-#define CE_ADM_ERR_SSP_SBE                             (0x1ULL <<  4)
-#define CE_ADM_ERR_SSP_MBE                             (0x1ULL <<  5)
-#define CE_ADM_ERR_CXM_CREDIT_OFLOW                    (0x1ULL <<  6)
-#define CE_ADM_ERR_DRE_SSP_REQ_INVAL                   (0x1ULL <<  7)
-#define CE_ADM_ERR_SSP_REQ_LONG                                (0x1ULL <<  8)
-#define CE_ADM_ERR_SSP_REQ_OFLOW                       (0x1ULL <<  9)
-#define CE_ADM_ERR_SSP_REQ_SHORT                       (0x1ULL << 10)
-#define CE_ADM_ERR_SSP_REQ_SIDEBAND                    (0x1ULL << 11)
-#define CE_ADM_ERR_SSP_REQ_ADDR_ERR                    (0x1ULL << 12)
-#define CE_ADM_ERR_SSP_REQ_BAD_BE                      (0x1ULL << 13)
-#define CE_ADM_ERR_PCIE_COMPL_TIMEOUT                  (0x1ULL << 14)
-#define CE_ADM_ERR_PCIE_UNEXP_COMPL                    (0x1ULL << 15)
-#define CE_ADM_ERR_PCIE_ERR_COMPL                      (0x1ULL << 16)
-#define CE_ADM_ERR_DRE_CREDIT_OFLOW                    (0x1ULL << 17)
-#define CE_ADM_ERR_DRE_SRAM_PE                         (0x1ULL << 18)
-#define CE_ADM_ERR_SSP_RSP_INVALID                     (0x1ULL << 19)
-#define CE_ADM_ERR_SSP_RSP_LONG                                (0x1ULL << 20)
-#define CE_ADM_ERR_SSP_RSP_SHORT                       (0x1ULL << 21)
-#define CE_ADM_ERR_SSP_RSP_SIDEBAND                    (0x1ULL << 22)
-#define CE_ADM_ERR_URE_SSP_RSP_UNEXP                   (0x1ULL << 23)
-#define CE_ADM_ERR_URE_SSP_WR_REQ_TIMEOUT              (0x1ULL << 24)
-#define CE_ADM_ERR_URE_SSP_RD_REQ_TIMEOUT              (0x1ULL << 25)
-#define CE_ADM_ERR_URE_ATE3240_PAGE_FAULT              (0x1ULL << 26)
-#define CE_ADM_ERR_URE_ATE40_PAGE_FAULT                        (0x1ULL << 27)
-#define CE_ADM_ERR_URE_CREDIT_OFLOW                    (0x1ULL << 28)
-#define CE_ADM_ERR_URE_SRAM_PE                         (0x1ULL << 29)
-#define CE_ADM_ERR_ADM_SSP_RSP_UNEXP                   (0x1ULL << 30)
-#define CE_ADM_ERR_ADM_SSP_REQ_TIMEOUT                 (0x1ULL << 31)
-#define CE_ADM_ERR_MMR_ACCESS_ERROR                    (0x1ULL << 32)
-#define CE_ADM_ERR_MMR_ADDR_ERROR                      (0x1ULL << 33)
-#define CE_ADM_ERR_ADM_CREDIT_OFLOW                    (0x1ULL << 34)
-#define CE_ADM_ERR_ADM_SRAM_PE                         (0x1ULL << 35)
-#define CE_ADM_ERR_DTL1_MIN_PDATA_CREDIT_ERR           (0x1ULL << 36)
-#define CE_ADM_ERR_DTL1_INF_COMPL_CRED_UPDT_ERR                (0x1ULL << 37)
-#define CE_ADM_ERR_DTL1_INF_POSTED_CRED_UPDT_ERR       (0x1ULL << 38)
-#define CE_ADM_ERR_DTL1_INF_NPOSTED_CRED_UPDT_ERR      (0x1ULL << 39)
-#define CE_ADM_ERR_DTL1_COMP_HD_CRED_MAX_ERR           (0x1ULL << 40)
-#define CE_ADM_ERR_DTL1_COMP_D_CRED_MAX_ERR            (0x1ULL << 41)
-#define CE_ADM_ERR_DTL1_NPOSTED_HD_CRED_MAX_ERR                (0x1ULL << 42)
-#define CE_ADM_ERR_DTL1_NPOSTED_D_CRED_MAX_ERR         (0x1ULL << 43)
-#define CE_ADM_ERR_DTL1_POSTED_HD_CRED_MAX_ERR         (0x1ULL << 44)
-#define CE_ADM_ERR_DTL1_POSTED_D_CRED_MAX_ERR          (0x1ULL << 45)
-#define CE_ADM_ERR_DTL2_MIN_PDATA_CREDIT_ERR           (0x1ULL << 46)
-#define CE_ADM_ERR_DTL2_INF_COMPL_CRED_UPDT_ERR                (0x1ULL << 47)
-#define CE_ADM_ERR_DTL2_INF_POSTED_CRED_UPDT_ERR       (0x1ULL << 48)
-#define CE_ADM_ERR_DTL2_INF_NPOSTED_CRED_UPDT_ERR      (0x1ULL << 49)
-#define CE_ADM_ERR_DTL2_COMP_HD_CRED_MAX_ERR           (0x1ULL << 50)
-#define CE_ADM_ERR_DTL2_COMP_D_CRED_MAX_ERR            (0x1ULL << 51)
-#define CE_ADM_ERR_DTL2_NPOSTED_HD_CRED_MAX_ERR                (0x1ULL << 52)
-#define CE_ADM_ERR_DTL2_NPOSTED_D_CRED_MAX_ERR         (0x1ULL << 53)
-#define CE_ADM_ERR_DTL2_POSTED_HD_CRED_MAX_ERR         (0x1ULL << 54)
-#define CE_ADM_ERR_DTL2_POSTED_D_CRED_MAX_ERR          (0x1ULL << 55)
-#define CE_ADM_ERR_PORT1_PCIE_COR_ERR                  (0x1ULL << 56)
-#define CE_ADM_ERR_PORT1_PCIE_NFAT_ERR                 (0x1ULL << 57)
-#define CE_ADM_ERR_PORT1_PCIE_FAT_ERR                  (0x1ULL << 58)
-#define CE_ADM_ERR_PORT2_PCIE_COR_ERR                  (0x1ULL << 59)
-#define CE_ADM_ERR_PORT2_PCIE_NFAT_ERR                 (0x1ULL << 60)
-#define CE_ADM_ERR_PORT2_PCIE_FAT_ERR                  (0x1ULL << 61)
-
-/* ce_adm_ure_ups_buf_barrier_flush register bit masks and shifts */
-#define FLUSH_SEL_PORT1_PIPE0_SHFT     0
-#define FLUSH_SEL_PORT1_PIPE1_SHFT     4
-#define FLUSH_SEL_PORT1_PIPE2_SHFT     8
-#define FLUSH_SEL_PORT1_PIPE3_SHFT     12
-#define FLUSH_SEL_PORT2_PIPE0_SHFT     16
-#define FLUSH_SEL_PORT2_PIPE1_SHFT     20
-#define FLUSH_SEL_PORT2_PIPE2_SHFT     24
-#define FLUSH_SEL_PORT2_PIPE3_SHFT     28
-
-/* ce_dre_config1 register bit masks and shifts */
-#define CE_DRE_RO_ENABLE               (0x1ULL << 0)
-#define CE_DRE_DYN_RO_ENABLE           (0x1ULL << 1)
-#define CE_DRE_SUP_CONFIG_COMP_ERROR   (0x1ULL << 2)
-#define CE_DRE_SUP_IO_COMP_ERROR       (0x1ULL << 3)
-#define CE_DRE_ADDR_MODE_SHFT          4
-
-/* ce_dre_config_req_status register bit masks */
-#define CE_DRE_LAST_CONFIG_COMPLETION  (0x7ULL << 0)
-#define CE_DRE_DOWNSTREAM_CONFIG_ERROR (0x1ULL << 3)
-#define CE_DRE_CONFIG_COMPLETION_VALID (0x1ULL << 4)
-#define CE_DRE_CONFIG_REQUEST_ACTIVE   (0x1ULL << 5)
-
-/* ce_ure_control register bit masks & shifts */
-#define CE_URE_RD_MRG_ENABLE           (0x1ULL << 0)
-#define CE_URE_WRT_MRG_ENABLE1         (0x1ULL << 4)
-#define CE_URE_WRT_MRG_ENABLE2         (0x1ULL << 5)
-#define CE_URE_WRT_MRG_TIMER_SHFT      12
-#define CE_URE_WRT_MRG_TIMER_MASK      (0x7FFULL << CE_URE_WRT_MRG_TIMER_SHFT)
-#define CE_URE_WRT_MRG_TIMER(x)                (((u64)(x) << \
-                                         CE_URE_WRT_MRG_TIMER_SHFT) & \
-                                        CE_URE_WRT_MRG_TIMER_MASK)
-#define CE_URE_RSPQ_BYPASS_DISABLE     (0x1ULL << 24)
-#define CE_URE_UPS_DAT1_PAR_DISABLE    (0x1ULL << 32)
-#define CE_URE_UPS_HDR1_PAR_DISABLE    (0x1ULL << 33)
-#define CE_URE_UPS_DAT2_PAR_DISABLE    (0x1ULL << 34)
-#define CE_URE_UPS_HDR2_PAR_DISABLE    (0x1ULL << 35)
-#define CE_URE_ATE_PAR_DISABLE         (0x1ULL << 36)
-#define CE_URE_RCI_PAR_DISABLE         (0x1ULL << 37)
-#define CE_URE_RSPQ_PAR_DISABLE                (0x1ULL << 38)
-#define CE_URE_DNS_DAT_PAR_DISABLE     (0x1ULL << 39)
-#define CE_URE_DNS_HDR_PAR_DISABLE     (0x1ULL << 40)
-#define CE_URE_MALFORM_DISABLE         (0x1ULL << 44)
-#define CE_URE_UNSUP_DISABLE           (0x1ULL << 45)
-
-/* ce_ure_page_map register bit masks & shifts */
-#define CE_URE_ATE3240_ENABLE          (0x1ULL << 0)
-#define CE_URE_ATE40_ENABLE            (0x1ULL << 1)
-#define CE_URE_PAGESIZE_SHFT           4
-#define CE_URE_PAGESIZE_MASK           (0x7ULL << CE_URE_PAGESIZE_SHFT)
-#define CE_URE_4K_PAGESIZE             (0x0ULL << CE_URE_PAGESIZE_SHFT)
-#define CE_URE_16K_PAGESIZE            (0x1ULL << CE_URE_PAGESIZE_SHFT)
-#define CE_URE_64K_PAGESIZE            (0x2ULL << CE_URE_PAGESIZE_SHFT)
-#define CE_URE_128K_PAGESIZE           (0x3ULL << CE_URE_PAGESIZE_SHFT)
-#define CE_URE_256K_PAGESIZE           (0x4ULL << CE_URE_PAGESIZE_SHFT)
-
-/* ce_ure_pipe_sel register bit masks & shifts */
-#define PKT_TRAFIC_SHRT                        16
-#define BUS_SRC_ID_SHFT                        8
-#define DEV_SRC_ID_SHFT                        3
-#define FNC_SRC_ID_SHFT                        0
-#define CE_URE_TC_MASK                 (0x07ULL << PKT_TRAFIC_SHRT)
-#define CE_URE_BUS_MASK                        (0xFFULL << BUS_SRC_ID_SHFT)
-#define CE_URE_DEV_MASK                        (0x1FULL << DEV_SRC_ID_SHFT)
-#define CE_URE_FNC_MASK                        (0x07ULL << FNC_SRC_ID_SHFT)
-#define CE_URE_PIPE_BUS(b)             (((u64)(b) << BUS_SRC_ID_SHFT) & \
-                                        CE_URE_BUS_MASK)
-#define CE_URE_PIPE_DEV(d)             (((u64)(d) << DEV_SRC_ID_SHFT) & \
-                                        CE_URE_DEV_MASK)
-#define CE_URE_PIPE_FNC(f)             (((u64)(f) << FNC_SRC_ID_SHFT) & \
-                                        CE_URE_FNC_MASK)
-
-#define CE_URE_SEL1_SHFT               0
-#define CE_URE_SEL2_SHFT               20
-#define CE_URE_SEL3_SHFT               40
-#define CE_URE_SEL1_MASK               (0x7FFFFULL << CE_URE_SEL1_SHFT)
-#define CE_URE_SEL2_MASK               (0x7FFFFULL << CE_URE_SEL2_SHFT)
-#define CE_URE_SEL3_MASK               (0x7FFFFULL << CE_URE_SEL3_SHFT)
-
-
-/* ce_ure_pipe_mask register bit masks & shifts */
-#define CE_URE_MASK1_SHFT              0
-#define CE_URE_MASK2_SHFT              20
-#define CE_URE_MASK3_SHFT              40
-#define CE_URE_MASK1_MASK              (0x7FFFFULL << CE_URE_MASK1_SHFT)
-#define CE_URE_MASK2_MASK              (0x7FFFFULL << CE_URE_MASK2_SHFT)
-#define CE_URE_MASK3_MASK              (0x7FFFFULL << CE_URE_MASK3_SHFT)
-
-
-/* ce_ure_pcie_control1 register bit masks & shifts */
-#define CE_URE_SI                      (0x1ULL << 0)
-#define CE_URE_ELAL_SHFT               4
-#define CE_URE_ELAL_MASK               (0x7ULL << CE_URE_ELAL_SHFT)
-#define CE_URE_ELAL_SET(n)             (((u64)(n) << CE_URE_ELAL_SHFT) & \
-                                        CE_URE_ELAL_MASK)
-#define CE_URE_ELAL1_SHFT              8
-#define CE_URE_ELAL1_MASK              (0x7ULL << CE_URE_ELAL1_SHFT)
-#define CE_URE_ELAL1_SET(n)            (((u64)(n) << CE_URE_ELAL1_SHFT) & \
-                                        CE_URE_ELAL1_MASK)
-#define CE_URE_SCC                     (0x1ULL << 12)
-#define CE_URE_PN1_SHFT                        16
-#define CE_URE_PN1_MASK                        (0xFFULL << CE_URE_PN1_SHFT)
-#define CE_URE_PN2_SHFT                        24
-#define CE_URE_PN2_MASK                        (0xFFULL << CE_URE_PN2_SHFT)
-#define CE_URE_PN1_SET(n)              (((u64)(n) << CE_URE_PN1_SHFT) & \
-                                        CE_URE_PN1_MASK)
-#define CE_URE_PN2_SET(n)              (((u64)(n) << CE_URE_PN2_SHFT) & \
-                                        CE_URE_PN2_MASK)
-
-/* ce_ure_pcie_control2 register bit masks & shifts */
-#define CE_URE_ABP                     (0x1ULL << 0)
-#define CE_URE_PCP                     (0x1ULL << 1)
-#define CE_URE_MSP                     (0x1ULL << 2)
-#define CE_URE_AIP                     (0x1ULL << 3)
-#define CE_URE_PIP                     (0x1ULL << 4)
-#define CE_URE_HPS                     (0x1ULL << 5)
-#define CE_URE_HPC                     (0x1ULL << 6)
-#define CE_URE_SPLV_SHFT               7
-#define CE_URE_SPLV_MASK               (0xFFULL << CE_URE_SPLV_SHFT)
-#define CE_URE_SPLV_SET(n)             (((u64)(n) << CE_URE_SPLV_SHFT) & \
-                                        CE_URE_SPLV_MASK)
-#define CE_URE_SPLS_SHFT               15
-#define CE_URE_SPLS_MASK               (0x3ULL << CE_URE_SPLS_SHFT)
-#define CE_URE_SPLS_SET(n)             (((u64)(n) << CE_URE_SPLS_SHFT) & \
-                                        CE_URE_SPLS_MASK)
-#define CE_URE_PSN1_SHFT               19
-#define CE_URE_PSN1_MASK               (0x1FFFULL << CE_URE_PSN1_SHFT)
-#define CE_URE_PSN2_SHFT               32
-#define CE_URE_PSN2_MASK               (0x1FFFULL << CE_URE_PSN2_SHFT)
-#define CE_URE_PSN1_SET(n)             (((u64)(n) << CE_URE_PSN1_SHFT) & \
-                                        CE_URE_PSN1_MASK)
-#define CE_URE_PSN2_SET(n)             (((u64)(n) << CE_URE_PSN2_SHFT) & \
-                                        CE_URE_PSN2_MASK)
-
-/*
- * PIO address space ranges for CE
- */
-
-/* Local CE Registers Space */
-#define CE_PIO_MMR                     0x00000000
-#define CE_PIO_MMR_LEN                 0x04000000
-
-/* PCI Compatible Config Space */
-#define CE_PIO_CONFIG_SPACE            0x04000000
-#define CE_PIO_CONFIG_SPACE_LEN                0x04000000
-
-/* PCI I/O Space Alias */
-#define CE_PIO_IO_SPACE_ALIAS          0x08000000
-#define CE_PIO_IO_SPACE_ALIAS_LEN      0x08000000
-
-/* PCI Enhanced Config Space */
-#define CE_PIO_E_CONFIG_SPACE          0x10000000
-#define CE_PIO_E_CONFIG_SPACE_LEN      0x10000000
-
-/* PCI I/O Space */
-#define CE_PIO_IO_SPACE                        0x100000000
-#define CE_PIO_IO_SPACE_LEN            0x100000000
-
-/* PCI MEM Space */
-#define CE_PIO_MEM_SPACE               0x200000000
-#define CE_PIO_MEM_SPACE_LEN           TIO_HWIN_SIZE
-
-
-/*
- * CE PCI Enhanced Config Space shifts & masks
- */
-#define CE_E_CONFIG_BUS_SHFT           20
-#define CE_E_CONFIG_BUS_MASK           (0xFF << CE_E_CONFIG_BUS_SHFT)
-#define CE_E_CONFIG_DEVICE_SHFT                15
-#define CE_E_CONFIG_DEVICE_MASK                (0x1F << CE_E_CONFIG_DEVICE_SHFT)
-#define CE_E_CONFIG_FUNC_SHFT          12
-#define CE_E_CONFIG_FUNC_MASK          (0x7  << CE_E_CONFIG_FUNC_SHFT)
-
-#endif /* __ASM_IA64_SN_TIOCE_H__ */
diff --git a/arch/ia64/include/asm/sn/tioce_provider.h b/arch/ia64/include/asm/sn/tioce_provider.h
deleted file mode 100644 (file)
index 32c32f3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_CE_PROVIDER_H
-#define _ASM_IA64_SN_CE_PROVIDER_H
-
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/tioce.h>
-
-/*
- * Common TIOCE structure shared between the prom and kernel
- *
- * DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES TO THE
- * PROM VERSION.
- */
-struct tioce_common {
-       struct pcibus_bussoft   ce_pcibus;      /* common pciio header */
-
-       u32             ce_rev;
-       u64             ce_kernel_private;
-       u64             ce_prom_private;
-};
-
-struct tioce_kernel {
-       struct tioce_common     *ce_common;
-       spinlock_t              ce_lock;
-       struct list_head        ce_dmamap_list;
-
-       u64             ce_ate40_shadow[TIOCE_NUM_M40_ATES];
-       u64             ce_ate3240_shadow[TIOCE_NUM_M3240_ATES];
-       u32             ce_ate3240_pagesize;
-
-       u8                      ce_port1_secondary;
-
-       /* per-port resources */
-       struct {
-               int             dirmap_refcnt;
-               u64     dirmap_shadow;
-       } ce_port[TIOCE_NUM_PORTS];
-};
-
-struct tioce_dmamap {
-       struct list_head        ce_dmamap_list; /* headed by tioce_kernel */
-       u32             refcnt;
-
-       u64             nbytes;         /* # bytes mapped */
-
-       u64             ct_start;       /* coretalk start address */
-       u64             pci_start;      /* bus start address */
-
-       u64             __iomem *ate_hw;/* hw ptr of first ate in map */
-       u64             *ate_shadow;    /* shadow ptr of firat ate */
-       u16             ate_count;      /* # ate's in the map */
-};
-
-extern int tioce_init_provider(void);
-
-#endif  /* __ASM_IA64_SN_CE_PROVIDER_H */
diff --git a/arch/ia64/include/asm/sn/tiocp.h b/arch/ia64/include/asm/sn/tiocp.h
deleted file mode 100644 (file)
index e8ad0bb..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_PCI_TIOCP_H
-#define _ASM_IA64_SN_PCI_TIOCP_H
-
-#define TIOCP_HOST_INTR_ADDR            0x003FFFFFFFFFFFFFUL
-#define TIOCP_PCI64_CMDTYPE_MEM         (0x1ull << 60)
-#define TIOCP_PCI64_CMDTYPE_MSI         (0x3ull << 60)
-
-
-/*****************************************************************************
- *********************** TIOCP MMR structure mapping ***************************
- *****************************************************************************/
-
-struct tiocp{
-
-    /* 0x000000-0x00FFFF -- Local Registers */
-
-    /* 0x000000-0x000057 -- (Legacy Widget Space) Configuration */
-    u64                cp_id;                          /* 0x000000 */
-    u64                cp_stat;                        /* 0x000008 */
-    u64                cp_err_upper;                   /* 0x000010 */
-    u64                cp_err_lower;                   /* 0x000018 */
-    #define cp_err cp_err_lower
-    u64                cp_control;                     /* 0x000020 */
-    u64                cp_req_timeout;                 /* 0x000028 */
-    u64                cp_intr_upper;                  /* 0x000030 */
-    u64                cp_intr_lower;                  /* 0x000038 */
-    #define cp_intr cp_intr_lower
-    u64                cp_err_cmdword;                 /* 0x000040 */
-    u64                _pad_000048;                    /* 0x000048 */
-    u64                cp_tflush;                      /* 0x000050 */
-
-    /* 0x000058-0x00007F -- Bridge-specific Configuration */
-    u64                cp_aux_err;                     /* 0x000058 */
-    u64                cp_resp_upper;                  /* 0x000060 */
-    u64                cp_resp_lower;                  /* 0x000068 */
-    #define cp_resp cp_resp_lower
-    u64                cp_tst_pin_ctrl;                /* 0x000070 */
-    u64                cp_addr_lkerr;                  /* 0x000078 */
-
-    /* 0x000080-0x00008F -- PMU & MAP */
-    u64                cp_dir_map;                     /* 0x000080 */
-    u64                _pad_000088;                    /* 0x000088 */
-
-    /* 0x000090-0x00009F -- SSRAM */
-    u64                cp_map_fault;                   /* 0x000090 */
-    u64                _pad_000098;                    /* 0x000098 */
-
-    /* 0x0000A0-0x0000AF -- Arbitration */
-    u64                cp_arb;                         /* 0x0000A0 */
-    u64                _pad_0000A8;                    /* 0x0000A8 */
-
-    /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */
-    u64                cp_ate_parity_err;              /* 0x0000B0 */
-    u64                _pad_0000B8;                    /* 0x0000B8 */
-
-    /* 0x0000C0-0x0000FF -- PCI/GIO */
-    u64                cp_bus_timeout;                 /* 0x0000C0 */
-    u64                cp_pci_cfg;                     /* 0x0000C8 */
-    u64                cp_pci_err_upper;               /* 0x0000D0 */
-    u64                cp_pci_err_lower;               /* 0x0000D8 */
-    #define cp_pci_err cp_pci_err_lower
-    u64                _pad_0000E0[4];                 /* 0x0000{E0..F8} */
-
-    /* 0x000100-0x0001FF -- Interrupt */
-    u64                cp_int_status;                  /* 0x000100 */
-    u64                cp_int_enable;                  /* 0x000108 */
-    u64                cp_int_rst_stat;                /* 0x000110 */
-    u64                cp_int_mode;                    /* 0x000118 */
-    u64                cp_int_device;                  /* 0x000120 */
-    u64                cp_int_host_err;                /* 0x000128 */
-    u64                cp_int_addr[8];                 /* 0x0001{30,,,68} */
-    u64                cp_err_int_view;                /* 0x000170 */
-    u64                cp_mult_int;                    /* 0x000178 */
-    u64                cp_force_always[8];             /* 0x0001{80,,,B8} */
-    u64                cp_force_pin[8];                /* 0x0001{C0,,,F8} */
-
-    /* 0x000200-0x000298 -- Device */
-    u64                cp_device[4];                   /* 0x0002{00,,,18} */
-    u64                _pad_000220[4];                 /* 0x0002{20,,,38} */
-    u64                cp_wr_req_buf[4];               /* 0x0002{40,,,58} */
-    u64                _pad_000260[4];                 /* 0x0002{60,,,78} */
-    u64                cp_rrb_map[2];                  /* 0x0002{80,,,88} */
-    #define cp_even_resp cp_rrb_map[0]                 /* 0x000280 */
-    #define cp_odd_resp  cp_rrb_map[1]                 /* 0x000288 */
-    u64                cp_resp_status;                 /* 0x000290 */
-    u64                cp_resp_clear;                  /* 0x000298 */
-
-    u64                _pad_0002A0[12];                /* 0x0002{A0..F8} */
-
-    /* 0x000300-0x0003F8 -- Buffer Address Match Registers */
-    struct {
-       u64     upper;                          /* 0x0003{00,,,F0} */
-       u64     lower;                          /* 0x0003{08,,,F8} */
-    } cp_buf_addr_match[16];
-
-    /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */
-    struct {
-       u64     flush_w_touch;                  /* 0x000{400,,,5C0} */
-       u64     flush_wo_touch;                 /* 0x000{408,,,5C8} */
-       u64     inflight;                       /* 0x000{410,,,5D0} */
-       u64     prefetch;                       /* 0x000{418,,,5D8} */
-       u64     total_pci_retry;                /* 0x000{420,,,5E0} */
-       u64     max_pci_retry;                  /* 0x000{428,,,5E8} */
-       u64     max_latency;                    /* 0x000{430,,,5F0} */
-       u64     clear_all;                      /* 0x000{438,,,5F8} */
-    } cp_buf_count[8];
-
-
-    /* 0x000600-0x0009FF -- PCI/X registers */
-    u64                cp_pcix_bus_err_addr;           /* 0x000600 */
-    u64                cp_pcix_bus_err_attr;           /* 0x000608 */
-    u64                cp_pcix_bus_err_data;           /* 0x000610 */
-    u64                cp_pcix_pio_split_addr;         /* 0x000618 */
-    u64                cp_pcix_pio_split_attr;         /* 0x000620 */
-    u64                cp_pcix_dma_req_err_attr;       /* 0x000628 */
-    u64                cp_pcix_dma_req_err_addr;       /* 0x000630 */
-    u64                cp_pcix_timeout;                /* 0x000638 */
-
-    u64                _pad_000640[24];                /* 0x000{640,,,6F8} */
-
-    /* 0x000700-0x000737 -- Debug Registers */
-    u64                cp_ct_debug_ctl;                /* 0x000700 */
-    u64                cp_br_debug_ctl;                /* 0x000708 */
-    u64                cp_mux3_debug_ctl;              /* 0x000710 */
-    u64                cp_mux4_debug_ctl;              /* 0x000718 */
-    u64                cp_mux5_debug_ctl;              /* 0x000720 */
-    u64                cp_mux6_debug_ctl;              /* 0x000728 */
-    u64                cp_mux7_debug_ctl;              /* 0x000730 */
-
-    u64                _pad_000738[89];                /* 0x000{738,,,9F8} */
-
-    /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */
-    struct {
-       u64     cp_buf_addr;                    /* 0x000{A00,,,AF0} */
-       u64     cp_buf_attr;                    /* 0X000{A08,,,AF8} */
-    } cp_pcix_read_buf_64[16];
-
-    struct {
-       u64     cp_buf_addr;                    /* 0x000{B00,,,BE0} */
-       u64     cp_buf_attr;                    /* 0x000{B08,,,BE8} */
-       u64     cp_buf_valid;                   /* 0x000{B10,,,BF0} */
-       u64     __pad1;                         /* 0x000{B18,,,BF8} */
-    } cp_pcix_write_buf_64[8];
-
-    /* End of Local Registers -- Start of Address Map space */
-
-    char       _pad_000c00[0x010000 - 0x000c00];
-
-    /* 0x010000-0x011FF8 -- Internal ATE RAM (Auto Parity Generation) */
-    u64                cp_int_ate_ram[1024];           /* 0x010000-0x011FF8 */
-
-    char       _pad_012000[0x14000 - 0x012000];
-
-    /* 0x014000-0x015FF8 -- Internal ATE RAM (Manual Parity Generation) */
-    u64                cp_int_ate_ram_mp[1024];        /* 0x014000-0x015FF8 */
-
-    char       _pad_016000[0x18000 - 0x016000];
-
-    /* 0x18000-0x197F8 -- TIOCP Write Request Ram */
-    u64                cp_wr_req_lower[256];           /* 0x18000 - 0x187F8 */
-    u64                cp_wr_req_upper[256];           /* 0x18800 - 0x18FF8 */
-    u64                cp_wr_req_parity[256];          /* 0x19000 - 0x197F8 */
-
-    char       _pad_019800[0x1C000 - 0x019800];
-
-    /* 0x1C000-0x1EFF8 -- TIOCP Read Response Ram */
-    u64                cp_rd_resp_lower[512];          /* 0x1C000 - 0x1CFF8 */
-    u64                cp_rd_resp_upper[512];          /* 0x1D000 - 0x1DFF8 */
-    u64                cp_rd_resp_parity[512];         /* 0x1E000 - 0x1EFF8 */
-
-    char       _pad_01F000[0x20000 - 0x01F000];
-
-    /* 0x020000-0x021FFF -- Host Device (CP) Configuration Space (not used)  */
-    char       _pad_020000[0x021000 - 0x20000];
-
-    /* 0x021000-0x027FFF -- PCI Device Configuration Spaces */
-    union {
-       u8      c[0x1000 / 1];                  /* 0x02{0000,,,7FFF} */
-       u16     s[0x1000 / 2];                  /* 0x02{0000,,,7FFF} */
-       u32     l[0x1000 / 4];                  /* 0x02{0000,,,7FFF} */
-       u64     d[0x1000 / 8];                  /* 0x02{0000,,,7FFF} */
-       union {
-           u8  c[0x100 / 1];
-           u16 s[0x100 / 2];
-           u32 l[0x100 / 4];
-           u64 d[0x100 / 8];
-       } f[8];
-    } cp_type0_cfg_dev[7];                             /* 0x02{1000,,,7FFF} */
-
-    /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */
-    union {
-       u8      c[0x1000 / 1];                  /* 0x028000-0x029000 */
-       u16     s[0x1000 / 2];                  /* 0x028000-0x029000 */
-       u32     l[0x1000 / 4];                  /* 0x028000-0x029000 */
-       u64     d[0x1000 / 8];                  /* 0x028000-0x029000 */
-       union {
-           u8  c[0x100 / 1];
-           u16 s[0x100 / 2];
-           u32 l[0x100 / 4];
-           u64 d[0x100 / 8];
-       } f[8];
-    } cp_type1_cfg;                                    /* 0x028000-0x029000 */
-
-    char               _pad_029000[0x030000-0x029000];
-
-    /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */
-    union {
-       u8      c[8 / 1];
-       u16     s[8 / 2];
-       u32     l[8 / 4];
-       u64     d[8 / 8];
-    } cp_pci_iack;                                     /* 0x030000-0x030007 */
-
-    char               _pad_030007[0x040000-0x030008];
-
-    /* 0x040000-0x040007 -- PCIX Special Cycle */
-    union {
-       u8      c[8 / 1];
-       u16     s[8 / 2];
-       u32     l[8 / 4];
-       u64     d[8 / 8];
-    } cp_pcix_cycle;                                   /* 0x040000-0x040007 */
-
-    char               _pad_040007[0x200000-0x040008];
-
-    /* 0x200000-0x7FFFFF -- PCI/GIO Device Spaces */
-    union {
-       u8      c[0x100000 / 1];
-       u16     s[0x100000 / 2];
-       u32     l[0x100000 / 4];
-       u64     d[0x100000 / 8];
-    } cp_devio_raw[6];                                 /* 0x200000-0x7FFFFF */
-
-    #define cp_devio(n)  cp_devio_raw[((n)<2)?(n*2):(n+2)]
-
-    char               _pad_800000[0xA00000-0x800000];
-
-    /* 0xA00000-0xBFFFFF -- PCI/GIO Device Spaces w/flush  */
-    union {
-       u8      c[0x100000 / 1];
-       u16     s[0x100000 / 2];
-       u32     l[0x100000 / 4];
-       u64     d[0x100000 / 8];
-    } cp_devio_raw_flush[6];                           /* 0xA00000-0xBFFFFF */
-
-    #define cp_devio_flush(n)  cp_devio_raw_flush[((n)<2)?(n*2):(n+2)]
-
-};
-
-#endif         /* _ASM_IA64_SN_PCI_TIOCP_H */
diff --git a/arch/ia64/include/asm/sn/tiocx.h b/arch/ia64/include/asm/sn/tiocx.h
deleted file mode 100644 (file)
index d297284..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_TIO_TIOCX_H
-#define _ASM_IA64_SN_TIO_TIOCX_H
-
-#ifdef __KERNEL__
-
-struct cx_id_s {
-       unsigned int part_num;
-       unsigned int mfg_num;
-       int nasid;
-};
-
-struct cx_dev {
-       struct cx_id_s cx_id;
-       int bt;                         /* board/blade type */
-       void *soft;                     /* driver specific */
-       struct hubdev_info *hubdev;
-       struct device dev;
-       struct cx_drv *driver;
-};
-
-struct cx_device_id {
-       unsigned int part_num;
-       unsigned int mfg_num;
-};
-
-struct cx_drv {
-       char *name;
-       const struct cx_device_id *id_table;
-       struct device_driver driver;
-       int (*probe) (struct cx_dev * dev, const struct cx_device_id * id);
-       int (*remove) (struct cx_dev * dev);
-};
-
-/* create DMA address by stripping AS bits */
-#define TIOCX_DMA_ADDR(a) (u64)((u64)(a) & 0xffffcfffffffffUL)
-
-#define TIOCX_TO_TIOCX_DMA_ADDR(a) (u64)(((u64)(a) & 0xfffffffff) |  \
-                                  ((((u64)(a)) & 0xffffc000000000UL) <<2))
-
-#define TIO_CE_ASIC_PARTNUM 0xce00
-#define TIOCX_CORELET 3
-
-/* These are taken from tio_mmr_as.h */
-#define TIO_ICE_FRZ_CFG               TIO_MMR_ADDR_MOD(0x00000000b0008100UL)
-#define TIO_ICE_PMI_TX_CFG            TIO_MMR_ADDR_MOD(0x00000000b000b100UL)
-#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL)
-#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL
-
-#define to_cx_dev(n) container_of(n, struct cx_dev, dev)
-#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver)
-
-extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int);
-extern void tiocx_irq_free(struct sn_irq_info *);
-extern int cx_device_unregister(struct cx_dev *);
-extern int cx_device_register(nasid_t, int, int, struct hubdev_info *, int);
-extern int cx_driver_unregister(struct cx_drv *);
-extern int cx_driver_register(struct cx_drv *);
-extern u64 tiocx_dma_addr(u64 addr);
-extern u64 tiocx_swin_base(int nasid);
-extern void tiocx_mmr_store(int nasid, u64 offset, u64 value);
-extern u64 tiocx_mmr_load(int nasid, u64 offset);
-
-#endif                         //  __KERNEL__
-#endif                         // _ASM_IA64_SN_TIO_TIOCX__
diff --git a/arch/ia64/include/asm/sn/types.h b/arch/ia64/include/asm/sn/types.h
deleted file mode 100644 (file)
index 8e04ee2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc.  All Rights Reserved.
- * Copyright (C) 1999 by Ralf Baechle
- */
-#ifndef _ASM_IA64_SN_TYPES_H
-#define _ASM_IA64_SN_TYPES_H
-
-#include <linux/types.h>
-
-typedef unsigned long  cpuid_t;
-typedef signed short   nasid_t;        /* node id in numa-as-id space */
-typedef signed char    partid_t;       /* partition ID type */
-typedef unsigned int    moduleid_t;     /* user-visible module number type */
-typedef unsigned int    cmoduleid_t;    /* kernel compact module id type */
-typedef unsigned char  slotid_t;       /* slot (blade) within module */
-typedef unsigned char  slabid_t;       /* slab (asic) within slot */
-typedef u64 nic_t;
-typedef unsigned long iopaddr_t;
-typedef unsigned long paddr_t;
-typedef short cnodeid_t;
-
-#endif /* _ASM_IA64_SN_TYPES_H */
index b10f31e..9011e90 100644 (file)
@@ -69,7 +69,6 @@ extern void ia64_load_extra (struct task_struct *task);
        if (unlikely((current->thread.flags & IA64_THREAD_MIGRATION) &&        \
                     (task_cpu(current) !=                                     \
                                      task_thread_info(current)->last_cpu))) { \
-               platform_migrate(current);                                     \
                task_thread_info(current)->last_cpu = task_cpu(current);       \
        }                                                                      \
 } while (0)
index 86ec034..f1f257d 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
-#include <asm/machvec.h>
 
 #include <asm-generic/tlb.h>
 
index 71df93e..48d4526 100644 (file)
@@ -2,12 +2,29 @@
 #ifndef _ASM_IA64_UV_UV_H
 #define _ASM_IA64_UV_UV_H
 
-#include <asm/sn/simulator.h>
+#ifdef CONFIG_IA64_SGI_UV
+extern bool ia64_is_uv;
 
 static inline int is_uv_system(void)
 {
-       /* temporary support for running on hardware simulator */
-       return IS_MEDUSA() || ia64_platform_is("uv");
+       return ia64_is_uv;
 }
 
+void __init uv_probe_system_type(void);
+void __init uv_setup(char **cmdline_p);
+#else /* CONFIG_IA64_SGI_UV */
+static inline int is_uv_system(void)
+{
+       return false;
+}
+
+static inline void __init uv_probe_system_type(void)
+{
+}
+
+static inline void __init uv_setup(char **cmdline_p)
+{
+}
+#endif /* CONFIG_IA64_SGI_UV */
+
 #endif /* _ASM_IA64_UV_UV_H */
index 4ba0514..1a8df66 100644 (file)
@@ -10,15 +10,14 @@ endif
 extra-y        := head.o vmlinux.lds
 
 obj-y := entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o     \
-        irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o          \
+        irq_lsapic.o ivt.o pal.o patch.o process.o perfmon.o ptrace.o sal.o            \
         salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
-        unwind.o mca.o mca_asm.o topology.o dma-mapping.o
+        unwind.o mca.o mca_asm.o topology.o dma-mapping.o iosapic.o acpi.o \
+        acpi-ext.o
 
-obj-$(CONFIG_ACPI)             += acpi.o acpi-ext.o
 obj-$(CONFIG_IA64_BRL_EMU)     += brl_emu.o
 
 obj-$(CONFIG_IA64_PALINFO)     += palinfo.o
-obj-$(CONFIG_IOSAPIC)          += iosapic.o
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_SMP)              += smp.o smpboot.o
 obj-$(CONFIG_NUMA)             += numa.o
@@ -31,7 +30,7 @@ obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)  += uncached.o
 obj-$(CONFIG_AUDIT)            += audit.o
-obj-$(CONFIG_PCI_MSI)          += msi_ia64.o
+obj-y                          += msi_ia64.o
 mca_recovery-y                 += mca_drv.o mca_drv_asm.o
 obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
index c597ab5..70d1587 100644 (file)
@@ -31,7 +31,6 @@
 #include <acpi/processor.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
-#include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/numa.h>
 #include <asm/sal.h>
@@ -45,77 +44,6 @@ unsigned int acpi_cpei_phys_cpuid;
 
 unsigned long acpi_wakeup_address = 0;
 
-#ifdef CONFIG_IA64_GENERIC
-static unsigned long __init acpi_find_rsdp(void)
-{
-       unsigned long rsdp_phys = 0;
-
-       if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
-               rsdp_phys = efi.acpi20;
-       else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
-               printk(KERN_WARNING PREFIX
-                      "v1.0/r0.71 tables no longer supported\n");
-       return rsdp_phys;
-}
-
-const char __init *
-acpi_get_sysname(void)
-{
-       unsigned long rsdp_phys;
-       struct acpi_table_rsdp *rsdp;
-       struct acpi_table_xsdt *xsdt;
-       struct acpi_table_header *hdr;
-#ifdef CONFIG_INTEL_IOMMU
-       u64 i, nentries;
-#endif
-
-       rsdp_phys = acpi_find_rsdp();
-       if (!rsdp_phys) {
-               printk(KERN_ERR
-                      "ACPI 2.0 RSDP not found, default to \"dig\"\n");
-               return "dig";
-       }
-
-       rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys);
-       if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
-               printk(KERN_ERR
-                      "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
-               return "dig";
-       }
-
-       xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
-       hdr = &xsdt->header;
-       if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) {
-               printk(KERN_ERR
-                      "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
-               return "dig";
-       }
-
-       if (!strcmp(hdr->oem_id, "HP")) {
-               return "hpzx1";
-       } else if (!strcmp(hdr->oem_id, "SGI")) {
-               if (!strcmp(hdr->oem_table_id + 4, "UV"))
-                       return "uv";
-               else
-                       return "sn2";
-       }
-
-#ifdef CONFIG_INTEL_IOMMU
-       /* Look for Intel IOMMU */
-       nentries = (hdr->length - sizeof(*hdr)) /
-                        sizeof(xsdt->table_offset_entry[0]);
-       for (i = 0; i < nentries; i++) {
-               hdr = __va(xsdt->table_offset_entry[i]);
-               if (strncmp(hdr->signature, ACPI_SIG_DMAR,
-                       sizeof(ACPI_SIG_DMAR) - 1) == 0)
-                       return "dig_vtd";
-       }
-#endif
-
-       return "dig";
-}
-#endif /* CONFIG_IA64_GENERIC */
-
 #define ACPI_MAX_PLATFORM_INTERRUPTS   256
 
 /* Array to record platform interrupt vectors for generic interrupt routing. */
@@ -407,7 +335,7 @@ get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
        int pxm;
 
        pxm = pa->proximity_domain_lo;
-       if (ia64_platform_is("sn2") || acpi_srat_revision >= 2)
+       if (acpi_srat_revision >= 2)
                pxm += pa->proximity_domain_hi[0] << 8;
        return pxm;
 }
@@ -418,7 +346,7 @@ get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
        int pxm;
 
        pxm = ma->proximity_domain;
-       if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1)
+       if (acpi_srat_revision <= 1)
                pxm &= 0xff;
 
        return pxm;
@@ -710,9 +638,8 @@ int __init acpi_boot_init(void)
 
        if (acpi_table_parse_madt
            (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) {
-               if (!ia64_platform_is("sn2"))
-                       printk(KERN_ERR PREFIX
-                              "Error parsing MADT - no IOSAPIC entries\n");
+               printk(KERN_ERR PREFIX
+                      "Error parsing MADT - no IOSAPIC entries\n");
        }
 
        /* System-Level Interrupt Routing */
index ad7d996..4a32627 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/dma-direct.h>
-#include <linux/swiotlb.h>
 #include <linux/export.h>
 
 /* Set this to 1 if there is a HW IOMMU in the system */
@@ -9,13 +8,6 @@ int iommu_detected __read_mostly;
 const struct dma_map_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
-const struct dma_map_ops *dma_get_ops(struct device *dev)
-{
-       return dma_ops;
-}
-EXPORT_SYMBOL(dma_get_ops);
-
-#ifdef CONFIG_SWIOTLB
 void *arch_dma_alloc(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
@@ -33,9 +25,3 @@ long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
 {
        return page_to_pfn(virt_to_page(cpu_addr));
 }
-
-void __init swiotlb_dma_init(void)
-{
-       swiotlb_init(1);
-}
-#endif
index fe6e494..fad4db2 100644 (file)
  *     used as architecture-independent interrupt handling mechanism in Linux.
  *     As an IRQ is a number, we have to have
  *     IA-64 interrupt vector number <-> IRQ number mapping.  On smaller
- *     systems, we use one-to-one mapping between IA-64 vector and IRQ.  A
- *     platform can implement platform_irq_to_vector(irq) and
- *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
- *     Please see also arch/ia64/include/asm/hw_irq.h for those APIs.
+ *     systems, we use one-to-one mapping between IA-64 vector and IRQ.
  *
  * To sum up, there are three levels of mappings involved:
  *
@@ -96,7 +93,6 @@
 #include <asm/hw_irq.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
-#include <asm/machvec.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 
@@ -646,10 +642,8 @@ get_target_cpu (unsigned int gsi, int irq)
        if (!cpu_online(smp_processor_id()))
                return cpu_physical_id(smp_processor_id());
 
-#ifdef CONFIG_ACPI
        if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)
                return get_cpei_target_cpu();
-#endif
 
 #ifdef CONFIG_NUMA
        {
index 8ed81b2..0a8e5e5 100644 (file)
@@ -35,18 +35,6 @@ void ack_bad_irq(unsigned int irq)
        printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id());
 }
 
-#ifdef CONFIG_IA64_GENERIC
-ia64_vector __ia64_irq_to_vector(int irq)
-{
-       return irq_cfg[irq].vector;
-}
-
-unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
-{
-       return __this_cpu_read(vector_irq[vec]);
-}
-#endif
-
 /*
  * Interrupt statistics:
  */
@@ -73,17 +61,6 @@ void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
                irq_redir[irq] = (char) (redir & 0xff);
        }
 }
-
-bool is_affinity_mask_valid(const struct cpumask *cpumask)
-{
-       if (ia64_platform_is("sn2")) {
-               /* Only allow one CPU to be specified in the smp_affinity mask */
-               if (cpumask_weight(cpumask) != 1)
-                       return false;
-       }
-       return true;
-}
-
 #endif /* CONFIG_SMP */
 
 int __init arch_early_irq_init(void)
index ab87d6c..f102084 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/intrinsics.h>
 #include <asm/io.h>
 #include <asm/hw_irq.h>
-#include <asm/machvec.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
@@ -53,7 +52,6 @@
 #define IRQ_USED               (1)
 #define IRQ_RSVD               (2)
 
-/* These can be overridden in platform_irq_init */
 int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
 int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
 
@@ -250,7 +248,7 @@ void __setup_vector_irq(int cpu)
        }
 }
 
-#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+#ifdef CONFIG_SMP
 
 static enum vector_domain_type {
        VECTOR_DOMAIN_NONE,
@@ -314,7 +312,7 @@ void irq_complete_move(unsigned irq)
        cpumask_and(&cleanup_mask, &cfg->old_domain, cpu_online_mask);
        cfg->move_cleanup_count = cpumask_weight(&cleanup_mask);
        for_each_cpu(i, &cleanup_mask)
-               platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0);
+               ia64_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0);
        cfg->move_in_progress = 0;
 }
 
@@ -634,21 +632,16 @@ ia64_native_register_ipi(void)
 void __init
 init_IRQ (void)
 {
-#ifdef CONFIG_ACPI
        acpi_boot_init();
-#endif
        ia64_register_ipi();
        register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
 #ifdef CONFIG_SMP
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG)
        if (vector_domain_type != VECTOR_DOMAIN_NONE)
                register_percpu_irq(IA64_IRQ_MOVE_VECTOR, &irq_move_irqaction);
 #endif
-#endif
 #ifdef CONFIG_PERFMON
        pfm_init_percpu();
 #endif
-       platform_irq_init();
 }
 
 void
index 5de801a..b8356ed 100644 (file)
@@ -979,32 +979,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        return ret;
 }
 
-struct param_bsp_cfm {
-       unsigned long ip;
-       unsigned long *bsp;
-       unsigned long cfm;
-};
-
-static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg)
-{
-       unsigned long ip;
-       struct param_bsp_cfm *lp = arg;
-
-       do {
-               unw_get_ip(info, &ip);
-               if (ip == 0)
-                       break;
-               if (ip == lp->ip) {
-                       unw_get_bsp(info, (unsigned long*)&lp->bsp);
-                       unw_get_cfm(info, (unsigned long*)&lp->cfm);
-                       return;
-               }
-       } while (unw_unwind(info) >= 0);
-       lp->bsp = NULL;
-       lp->cfm = 0;
-       return;
-}
-
 unsigned long arch_deref_entry_point(void *entry)
 {
        return ((struct fnptr *)entry)->ip;
index 3b1dd54..efc9b56 100644 (file)
@@ -127,7 +127,6 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
        ia64_srlz_d();
        while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
                ia64_eoi();
-       platform_kernel_launch_event();
        rnk = (relocate_new_kernel_t)&code_addr;
        (*rnk)(image->head, image->start, ia64_boot_param,
                     GRANULEROUNDDOWN((unsigned long) pal_addr));
diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
deleted file mode 100644 (file)
index ebd8253..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <asm/machvec.h>
-
-#ifdef CONFIG_IA64_GENERIC
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/page.h>
-
-struct ia64_machine_vector ia64_mv = {
-       .mmiowb = ___ia64_mmiowb
-};
-EXPORT_SYMBOL(ia64_mv);
-
-static struct ia64_machine_vector * __init
-lookup_machvec (const char *name)
-{
-       extern struct ia64_machine_vector machvec_start[];
-       extern struct ia64_machine_vector machvec_end[];
-       struct ia64_machine_vector *mv;
-
-       for (mv = machvec_start; mv < machvec_end; ++mv)
-               if (strcmp (mv->name, name) == 0)
-                       return mv;
-
-       return 0;
-}
-
-void __init
-machvec_init (const char *name)
-{
-       struct ia64_machine_vector *mv;
-
-       if (!name)
-               name = acpi_get_sysname();
-       mv = lookup_machvec(name);
-       if (!mv)
-               panic("generic kernel failed to find machine vector for"
-                     " platform %s!", name);
-
-       ia64_mv = *mv;
-       printk(KERN_INFO "booting generic kernel on platform %s\n", name);
-}
-
-void __init
-machvec_init_from_cmdline(const char *cmdline)
-{
-       char str[64];
-       const char *start;
-       char *end;
-
-       if (! (start = strstr(cmdline, "machvec=")) )
-               return machvec_init(NULL);
-
-       strlcpy(str, start + strlen("machvec="), sizeof(str));
-       if ( (end = strchr(str, ' ')) )
-               *end = '\0';
-
-       return machvec_init(str);
-}
-
-#endif /* CONFIG_IA64_GENERIC */
-
-void
-machvec_setup (char **arg)
-{
-}
-EXPORT_SYMBOL(machvec_setup);
-
-void
-machvec_timer_interrupt (int irq, void *dev_id)
-{
-}
-EXPORT_SYMBOL(machvec_timer_interrupt);
index 79190d8..bf2cb92 100644 (file)
@@ -91,7 +91,6 @@
 #include <linux/gfp.h>
 
 #include <asm/delay.h>
-#include <asm/machvec.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
@@ -149,9 +148,7 @@ static ia64_mc_info_t               ia64_mc_info;
 #define CPE_HISTORY_LENGTH    5
 #define CMC_HISTORY_LENGTH    5
 
-#ifdef CONFIG_ACPI
 static struct timer_list cpe_poll_timer;
-#endif
 static struct timer_list cmc_poll_timer;
 /*
  * This variable tells whether we are currently in polling mode.
@@ -532,8 +529,6 @@ int mca_recover_range(unsigned long addr)
 }
 EXPORT_SYMBOL_GPL(mca_recover_range);
 
-#ifdef CONFIG_ACPI
-
 int cpe_vector = -1;
 int ia64_cpe_irq = -1;
 
@@ -595,9 +590,6 @@ out:
        return IRQ_HANDLED;
 }
 
-#endif /* CONFIG_ACPI */
-
-#ifdef CONFIG_ACPI
 /*
  * ia64_mca_register_cpev
  *
@@ -625,7 +617,6 @@ ia64_mca_register_cpev (int cpev)
        IA64_MCA_DEBUG("%s: corrected platform error "
                       "vector %#x registered\n", __func__, cpev);
 }
-#endif /* CONFIG_ACPI */
 
 /*
  * ia64_mca_cmc_vector_setup
@@ -744,7 +735,7 @@ ia64_mca_cmc_vector_enable_keventd(struct work_struct *unused)
 static void
 ia64_mca_wakeup(int cpu)
 {
-       platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
 /*
@@ -1490,7 +1481,7 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
        cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
        if (cpuid < nr_cpu_ids) {
-               platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
+               ia64_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
        } else {
                /* If no log record, switch out of polling mode */
                if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) {
@@ -1523,7 +1514,7 @@ static void
 ia64_mca_cmc_poll (struct timer_list *unused)
 {
        /* Trigger a CMC interrupt cascade  */
-       platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
+       ia64_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
                                                        IA64_IPI_DM_INT, 0);
 }
 
@@ -1540,8 +1531,6 @@ ia64_mca_cmc_poll (struct timer_list *unused)
  * Outputs
  *     handled
  */
-#ifdef CONFIG_ACPI
-
 static irqreturn_t
 ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
 {
@@ -1560,7 +1549,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
        cpuid = cpumask_next(cpuid+1, cpu_online_mask);
 
        if (cpuid < NR_CPUS) {
-               platform_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
+               ia64_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
        } else {
                /*
                 * If a log was recorded, increase our polling frequency,
@@ -1600,12 +1589,10 @@ static void
 ia64_mca_cpe_poll (struct timer_list *unused)
 {
        /* Trigger a CPE interrupt cascade  */
-       platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
+       ia64_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
                                                        IA64_IPI_DM_INT, 0);
 }
 
-#endif /* CONFIG_ACPI */
-
 static int
 default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data)
 {
@@ -1799,7 +1786,6 @@ static struct irqaction mca_wkup_irqaction = {
        .name =         "mca_wkup"
 };
 
-#ifdef CONFIG_ACPI
 static struct irqaction mca_cpe_irqaction = {
        .handler =      ia64_mca_cpe_int_handler,
        .name =         "cpe_hndlr"
@@ -1809,7 +1795,6 @@ static struct irqaction mca_cpep_irqaction = {
        .handler =      ia64_mca_cpe_int_caller,
        .name =         "cpe_poll"
 };
-#endif /* CONFIG_ACPI */
 
 /* Minimal format of the MCA/INIT stacks.  The pseudo processes that run on
  * these stacks can never sleep, they cannot return from the kernel to user
@@ -2081,10 +2066,8 @@ void __init ia64_mca_irq_init(void)
        /* Setup the MCA wakeup interrupt vector */
        register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
 
-#ifdef CONFIG_ACPI
        /* Setup the CPEI/P handler */
        register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
-#endif
 }
 
 /*
@@ -2112,7 +2095,6 @@ ia64_mca_late_init(void)
                          ia64_mca_cpu_online, NULL);
        IA64_MCA_DEBUG("%s: CMCI/P setup and enabled.\n", __func__);
 
-#ifdef CONFIG_ACPI
        /* Setup the CPEI/P vector and handler */
        cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
        timer_setup(&cpe_poll_timer, ia64_mca_cpe_poll, 0);
@@ -2143,7 +2125,6 @@ ia64_mca_late_init(void)
                        IA64_MCA_DEBUG("%s: CPEP setup and enabled.\n", __func__);
                }
        }
-#endif
 
        return 0;
 }
index cd7972e..4d0ab32 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 
 #include <asm/delay.h>
-#include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/sal.h>
index 326448f..1a42ba8 100644 (file)
@@ -914,10 +914,14 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo
 void
 module_arch_cleanup (struct module *mod)
 {
-       if (mod->arch.init_unw_table)
+       if (mod->arch.init_unw_table) {
                unw_remove_unwind_table(mod->arch.init_unw_table);
-       if (mod->arch.core_unw_table)
+               mod->arch.init_unw_table = NULL;
+       }
+       if (mod->arch.core_unw_table) {
                unw_remove_unwind_table(mod->arch.core_unw_table);
+               mod->arch.core_unw_table = NULL;
+       }
 }
 
 void *dereference_module_function_descriptor(struct module *mod, void *ptr)
index 519d943..df5c28f 100644 (file)
@@ -43,7 +43,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
 }
 #endif /* CONFIG_SMP */
 
-int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct msi_msg  msg;
        unsigned long   dest_phys_id;
@@ -77,7 +77,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
        return 0;
 }
 
-void ia64_teardown_msi_irq(unsigned int irq)
+void arch_teardown_msi_irq(unsigned int irq)
 {
        destroy_irq(irq);
 }
@@ -111,23 +111,6 @@ static struct irq_chip ia64_msi_chip = {
        .irq_retrigger          = ia64_msi_retrigger_irq,
 };
 
-
-int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
-{
-       if (platform_setup_msi_irq)
-               return platform_setup_msi_irq(pdev, desc);
-
-       return ia64_setup_msi_irq(pdev, desc);
-}
-
-void arch_teardown_msi_irq(unsigned int irq)
-{
-       if (platform_teardown_msi_irq)
-               return platform_teardown_msi_irq(irq);
-
-       return ia64_teardown_msi_irq(irq);
-}
-
 #ifdef CONFIG_INTEL_IOMMU
 #ifdef CONFIG_SMP
 static int dmar_msi_set_affinity(struct irq_data *data,
index fe988c4..c902217 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <linux/dmar.h>
 #include <asm/iommu.h>
-#include <asm/machvec.h>
 #include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <asm/page.h>
@@ -22,8 +21,6 @@ int force_iommu __read_mostly = 1;
 int force_iommu __read_mostly;
 #endif
 
-int iommu_pass_through;
-
 static int __init pci_iommu_init(void)
 {
        if (iommu_detected)
@@ -34,24 +31,3 @@ static int __init pci_iommu_init(void)
 
 /* Must execute after PCI subsystem */
 fs_initcall(pci_iommu_init);
-
-void __init pci_iommu_alloc(void)
-{
-       /*
-        * The order of these functions is important for
-        * fall-back/fail-over reasons
-        */
-       detect_intel_iommu();
-
-#ifdef CONFIG_SWIOTLB
-       if (!iommu_detected) {
-#ifdef CONFIG_IA64_GENERIC
-               printk(KERN_INFO "PCI-DMA: Re-initialize machine vector.\n");
-               machvec_init("dig");
-               swiotlb_dma_init();
-#else
-               panic("Unable to find Intel IOMMU");
-#endif /* CONFIG_IA64_GENERIC */
-       }
-#endif /* CONFIG_SWIOTLB */
-}
index 9b2331a..c455ece 100644 (file)
@@ -110,13 +110,6 @@ check_versions (struct ia64_sal_systab *systab)
                sal_revision = SAL_VERSION_CODE(2, 8);
                sal_version = SAL_VERSION_CODE(0, 0);
        }
-
-       if (ia64_platform_is("sn2") && (sal_revision == SAL_VERSION_CODE(2, 9)))
-               /*
-                * SGI Altix has hard-coded version 2.9 in their prom
-                * but they actually implement 3.2, so let's fix it here.
-                */
-               sal_revision = SAL_VERSION_CODE(3, 2);
 }
 
 static void __init
@@ -256,7 +249,7 @@ check_sal_cache_flush (void)
         * Send ourselves a timer interrupt, wait until it's reported, and see
         * if SAL_CACHE_FLUSH drops it.
         */
-       platform_send_ipi(cpu, IA64_TIMER_VECTOR, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(cpu, IA64_TIMER_VECTOR, IA64_IPI_DM_INT, 0);
 
        while (!ia64_get_irr(IA64_TIMER_VECTOR))
                cpu_relax();
index c9cfa76..18de565 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/cpu.h>
+#include <linux/kdev_t.h>
 #include <linux/kernel.h>
 #include <linux/memblock.h>
 #include <linux/reboot.h>
@@ -41,6 +42,7 @@
 #include <linux/threads.h>
 #include <linux/screen_info.h>
 #include <linux/dmi.h>
+#include <linux/root_dev.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/efi.h>
@@ -50,7 +52,6 @@
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 
-#include <asm/machvec.h>
 #include <asm/mca.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/smp.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
-#include <asm/hpsim.h>
+#include <asm/uv/uv.h>
 
 #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
 # error "struct cpuinfo_ia64 too big!"
 #endif
 
+char ia64_platform_name[64];
+
 #ifdef CONFIG_SMP
 unsigned long __per_cpu_offset[NR_CPUS];
 EXPORT_SYMBOL(__per_cpu_offset);
@@ -260,11 +263,11 @@ __initcall(register_memory);
  * in kdump case. See the comment in sba_init() in sba_iommu.c.
  *
  * So, the only machvec that really supports loading the kdump kernel
- * over 4 GB is "sn2".
+ * over 4 GB is "uv".
  */
 static int __init check_crashkernel_memory(unsigned long pbase, size_t size)
 {
-       if (ia64_platform_is("sn2") || ia64_platform_is("uv"))
+       if (is_uv_system())
                return 1;
        else
                return pbase < (1UL << 32);
@@ -461,23 +464,44 @@ io_port_init (void)
 static inline int __init
 early_console_setup (char *cmdline)
 {
-       int earlycons = 0;
-
-#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
-       {
-               extern int sn_serial_console_early_setup(void);
-               if (!sn_serial_console_early_setup())
-                       earlycons++;
-       }
-#endif
 #ifdef CONFIG_EFI_PCDP
        if (!efi_setup_pcdp_console(cmdline))
-               earlycons++;
+               return 0;
 #endif
-       if (!simcons_register())
-               earlycons++;
+       return -1;
+}
+
+static void __init
+screen_info_setup(void)
+{
+       unsigned int orig_x, orig_y, num_cols, num_rows, font_height;
+
+       memset(&screen_info, 0, sizeof(screen_info));
+
+       if (!ia64_boot_param->console_info.num_rows ||
+           !ia64_boot_param->console_info.num_cols) {
+               printk(KERN_WARNING "invalid screen-info, guessing 80x25\n");
+               orig_x = 0;
+               orig_y = 0;
+               num_cols = 80;
+               num_rows = 25;
+               font_height = 16;
+       } else {
+               orig_x = ia64_boot_param->console_info.orig_x;
+               orig_y = ia64_boot_param->console_info.orig_y;
+               num_cols = ia64_boot_param->console_info.num_cols;
+               num_rows = ia64_boot_param->console_info.num_rows;
+               font_height = 400 / num_rows;
+       }
 
-       return (earlycons) ? 0 : -1;
+       screen_info.orig_x = orig_x;
+       screen_info.orig_y = orig_y;
+       screen_info.orig_video_cols  = num_cols;
+       screen_info.orig_video_lines = num_rows;
+       screen_info.orig_video_points = font_height;
+       screen_info.orig_video_mode = 3;        /* XXX fake */
+       screen_info.orig_video_isVGA = 1;       /* XXX fake */
+       screen_info.orig_video_ega_bx = 3;      /* XXX fake */
 }
 
 static inline void
@@ -536,35 +560,25 @@ setup_arch (char **cmdline_p)
        efi_init();
        io_port_init();
 
-#ifdef CONFIG_IA64_GENERIC
-       /* machvec needs to be parsed from the command line
-        * before parse_early_param() is called to ensure
-        * that ia64_mv is initialised before any command line
-        * settings may cause console setup to occur
-        */
-       machvec_init_from_cmdline(*cmdline_p);
-#endif
-
+       uv_probe_system_type();
        parse_early_param();
 
        if (early_console_setup(*cmdline_p) == 0)
                mark_bsp_online();
 
-#ifdef CONFIG_ACPI
        /* Initialize the ACPI boot-time table parser */
        acpi_table_init();
        early_acpi_boot_init();
-# ifdef CONFIG_ACPI_NUMA
+#ifdef CONFIG_ACPI_NUMA
        acpi_numa_init();
        acpi_numa_fixup();
-#  ifdef CONFIG_ACPI_HOTPLUG_CPU
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
        prefill_possible_map();
-#  endif
+#endif
        per_cpu_scan_finalize((cpumask_weight(&early_cpu_possible_map) == 0 ?
                32 : cpumask_weight(&early_cpu_possible_map)),
                additional_cpus > 0 ? additional_cpus : 0);
-# endif
-#endif /* CONFIG_APCI_BOOT */
+#endif /* CONFIG_ACPI_NUMA */
 
 #ifdef CONFIG_SMP
        smp_build_cpu_map();
@@ -614,10 +628,21 @@ setup_arch (char **cmdline_p)
        if (!nomca)
                ia64_mca_init();
 
-       platform_setup(cmdline_p);
-#ifndef CONFIG_IA64_HP_SIM
-       check_sal_cache_flush();
+       /*
+        * Default to /dev/sda2.  This assumes that the EFI partition
+        * is physical disk 1 partition 1 and the Linux root disk is
+        * physical disk 1 partition 2.
+        */
+       ROOT_DEV = Root_SDA2;           /* default to second partition on first drive */
+
+       if (is_uv_system())
+               uv_setup(cmdline_p);
+#ifdef CONFIG_SMP
+       else
+               init_smp_config();
 #endif
+
+       screen_info_setup();
        paging_init();
 
        clear_sched_clock_stable();
@@ -1046,7 +1071,6 @@ cpu_init (void)
                ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8);
                max_num_phys_stacked = num_phys_stacked;
        }
-       platform_cpu_init();
 }
 
 void __init
index e5044ae..d07ed65 100644 (file)
@@ -363,19 +363,19 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
 
                if (unlikely(restart)) {
                        switch (errno) {
-                             case ERESTART_RESTARTBLOCK:
-                             case ERESTARTNOHAND:
+                       case ERESTART_RESTARTBLOCK:
+                       case ERESTARTNOHAND:
                                scr->pt.r8 = EINTR;
                                /* note: scr->pt.r10 is already -1 */
                                break;
-
-                             case ERESTARTSYS:
+                       case ERESTARTSYS:
                                if ((ksig.ka.sa.sa_flags & SA_RESTART) == 0) {
                                        scr->pt.r8 = EINTR;
                                        /* note: scr->pt.r10 is already -1 */
                                        break;
                                }
-                             case ERESTARTNOINTR:
+                               /*FALLTHRU*/
+                       case ERESTARTNOINTR:
                                ia64_decrement_ip(&scr->pt);
                                restart = 0; /* don't restart twice if handle_signal() fails... */
                        }
index 133b633..de35c54 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/atomic.h>
 #include <asm/current.h>
 #include <asm/delay.h>
-#include <asm/machvec.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/page.h>
@@ -146,7 +145,7 @@ static inline void
 send_IPI_single (int dest_cpu, int op)
 {
        set_bit(op, &per_cpu(ipi_operation, dest_cpu));
-       platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
 /*
@@ -213,7 +212,7 @@ kdump_smp_send_init(void)
        for_each_online_cpu(cpu) {
                if (cpu != self_cpu) {
                        if(kdump_status[cpu] == 0)
-                               platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
+                               ia64_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
                }
        }
 }
@@ -224,7 +223,7 @@ kdump_smp_send_init(void)
 void
 smp_send_reschedule (int cpu)
 {
-       platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
 }
 EXPORT_SYMBOL_GPL(smp_send_reschedule);
 
@@ -234,7 +233,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule);
 static void
 smp_send_local_flush_tlb (int cpu)
 {
-       platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0);
 }
 
 void
index d0474a0..6501d9a 100644 (file)
@@ -47,7 +47,6 @@
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/machvec.h>
 #include <asm/mca.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -57,7 +56,6 @@
 #include <asm/sal.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
-#include <asm/sn/arch.h>
 
 #define SMP_DEBUG 0
 
@@ -468,7 +466,7 @@ do_boot_cpu (int sapicid, int cpu, struct task_struct *idle)
        Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
 
        set_brendez_area(cpu);
-       platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
+       ia64_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
 
        /*
         * Wait 10s total for the AP to start
@@ -658,11 +656,6 @@ int __cpu_disable(void)
                return (-EBUSY);
        }
 
-       if (ia64_platform_is("sn2")) {
-               if (!sn_cpu_disable_allowed(cpu))
-                       return -EBUSY;
-       }
-
        set_cpu_online(cpu, false);
 
        if (migrate_platform_irqs(cpu)) {
index 9ebe1d6..e14db25 100644 (file)
@@ -166,21 +166,3 @@ ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, u
                force_successful_syscall_return();
        return addr;
 }
-
-#ifndef CONFIG_PCI
-
-asmlinkage long
-sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
-                   void *buf)
-{
-       return -ENOSYS;
-}
-
-asmlinkage long
-sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
-                    void *buf)
-{
-       return -ENOSYS;
-}
-
-#endif /* CONFIG_PCI */
index 4ecd81b..1e95d32 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/platform_device.h>
 #include <linux/sched/cputime.h>
 
-#include <asm/machvec.h>
 #include <asm/delay.h>
 #include <asm/hw_irq.h>
 #include <asm/ptrace.h>
@@ -167,8 +166,6 @@ timer_interrupt (int irq, void *dev_id)
                return IRQ_HANDLED;
        }
 
-       platform_timer_interrupt(irq, dev_id);
-
        new_itm = local_cpu_data->itm_next;
 
        if (!time_after(ia64_get_itc(), new_itm))
index e311ee1..09fc385 100644 (file)
@@ -42,7 +42,6 @@ EXPORT_SYMBOL_GPL(arch_fix_phys_package_id);
 #ifdef CONFIG_HOTPLUG_CPU
 int __ref arch_register_cpu(int num)
 {
-#ifdef CONFIG_ACPI
        /*
         * If CPEI can be re-targeted or if this is not
         * CPEI target, then it is hotpluggable
@@ -50,7 +49,6 @@ int __ref arch_register_cpu(int num)
        if (can_cpei_retarget() || !is_cpu_cpei_target(num))
                sysfs_cpus[num].cpu.hotpluggable = 1;
        map_cpu_to_node(num, node_cpuid[num].nid);
-#endif
        return register_cpu(&sysfs_cpus[num].cpu, num);
 }
 EXPORT_SYMBOL(arch_register_cpu);
@@ -58,9 +56,7 @@ EXPORT_SYMBOL(arch_register_cpu);
 void __ref arch_unregister_cpu(int num)
 {
        unregister_cpu(&sysfs_cpus[num].cpu);
-#ifdef CONFIG_ACPI
        unmap_cpu_from_node(num, cpu_to_node(num));
-#endif
 }
 EXPORT_SYMBOL(arch_unregister_cpu);
 #else
index eb7d5df..2d4e65b 100644 (file)
@@ -1431,7 +1431,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /* no break */
+               /*FALLTHRU*/
              case LDS_IMM_OP:
              case LDSA_IMM_OP:
              case LDFS_OP:
@@ -1459,7 +1459,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /* no break */
+               /*FALLTHRU*/
              case LD_IMM_OP:
              case LDA_IMM_OP:
              case LDBIAS_IMM_OP:
@@ -1475,7 +1475,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                if (u.insn.x)
                        /* oops, really a semaphore op (cmpxchg, etc) */
                        goto failure;
-               /* no break */
+               /*FALLTHRU*/
              case ST_IMM_OP:
              case STREL_IMM_OP:
                ret = emulate_store_int(ifa, u.insn, regs);
index 16c6d37..3776ef2 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/pgtable.h>
 #include <linux/atomic.h>
 #include <asm/tlbflush.h>
-#include <asm/sn/arch.h>
 
 
 extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *);
@@ -129,10 +128,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
 
        preempt_disable();
 
-       if (ia64_platform_is("sn2"))
-               sn_flush_all_caches(uc_addr, IA64_GRANULE_SIZE);
-       else
-               flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE);
+       flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE);
 
        /* flush the just introduced uncached translation from the TLB */
        local_flush_tlb_all();
index 0da58cf..d9d4e21 100644 (file)
@@ -141,16 +141,6 @@ SECTIONS {
                __end___mckinley_e9_bundles = .;
        }
 
-#if defined(CONFIG_IA64_GENERIC)
-       /* Machine Vector */
-       . = ALIGN(16);
-       .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) {
-               machvec_start = .;
-               *(.machvec)
-               machvec_end = .;
-       }
-#endif
-
 #ifdef CONFIG_SMP
        . = ALIGN(PERCPU_PAGE_SIZE);
        __cpu0_per_cpu = .;
index d107eaf..c3e0246 100644 (file)
@@ -49,117 +49,3 @@ void memset_io(volatile void __iomem *dst, int c, long count)
        }
 }
 EXPORT_SYMBOL(memset_io);
-
-#ifdef CONFIG_IA64_GENERIC
-
-#undef __ia64_inb
-#undef __ia64_inw
-#undef __ia64_inl
-#undef __ia64_outb
-#undef __ia64_outw
-#undef __ia64_outl
-#undef __ia64_readb
-#undef __ia64_readw
-#undef __ia64_readl
-#undef __ia64_readq
-#undef __ia64_readb_relaxed
-#undef __ia64_readw_relaxed
-#undef __ia64_readl_relaxed
-#undef __ia64_readq_relaxed
-#undef __ia64_writeb
-#undef __ia64_writew
-#undef __ia64_writel
-#undef __ia64_writeq
-#undef __ia64_mmiowb
-
-unsigned int
-__ia64_inb (unsigned long port)
-{
-       return ___ia64_inb(port);
-}
-
-unsigned int
-__ia64_inw (unsigned long port)
-{
-       return ___ia64_inw(port);
-}
-
-unsigned int
-__ia64_inl (unsigned long port)
-{
-       return ___ia64_inl(port);
-}
-
-void
-__ia64_outb (unsigned char val, unsigned long port)
-{
-       ___ia64_outb(val, port);
-}
-
-void
-__ia64_outw (unsigned short val, unsigned long port)
-{
-       ___ia64_outw(val, port);
-}
-
-void
-__ia64_outl (unsigned int val, unsigned long port)
-{
-       ___ia64_outl(val, port);
-}
-
-unsigned char
-__ia64_readb (void __iomem *addr)
-{
-       return ___ia64_readb (addr);
-}
-
-unsigned short
-__ia64_readw (void __iomem *addr)
-{
-       return ___ia64_readw (addr);
-}
-
-unsigned int
-__ia64_readl (void __iomem *addr)
-{
-       return ___ia64_readl (addr);
-}
-
-unsigned long
-__ia64_readq (void __iomem *addr)
-{
-       return ___ia64_readq (addr);
-}
-
-unsigned char
-__ia64_readb_relaxed (void __iomem *addr)
-{
-       return ___ia64_readb (addr);
-}
-
-unsigned short
-__ia64_readw_relaxed (void __iomem *addr)
-{
-       return ___ia64_readw (addr);
-}
-
-unsigned int
-__ia64_readl_relaxed (void __iomem *addr)
-{
-       return ___ia64_readl (addr);
-}
-
-unsigned long
-__ia64_readq_relaxed (void __iomem *addr)
-{
-       return ___ia64_readq (addr);
-}
-
-void
-__ia64_mmiowb(void)
-{
-       ___ia64_mmiowb();
-}
-
-#endif /* CONFIG_IA64_GENERIC */
index 05490dd..921f3ef 100644 (file)
@@ -396,8 +396,7 @@ static void __meminit scatter_node_data(void)
  *
  * Each node's per-node area has a copy of the global pg_data_t list, so
  * we copy that to each node here, as well as setting the per-cpu pointer
- * to the local node data structure.  The active_cpus field of the per-node
- * structure gets setup by the platform_cpu_init() function later.
+ * to the local node data structure.
  */
 static void __init initialize_pernode_data(void)
 {
index aae75fd..678b98a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <linux/dma-noncoherent.h>
+#include <linux/dmar.h>
 #include <linux/efi.h>
 #include <linux/elf.h>
 #include <linux/memblock.h>
 #include <linux/proc_fs.h>
 #include <linux/bitops.h>
 #include <linux/kexec.h>
+#include <linux/swiotlb.h>
 
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/machvec.h>
 #include <asm/numa.h>
 #include <asm/patch.h>
 #include <asm/pgalloc.h>
@@ -67,7 +68,6 @@ __ia64_sync_icache_dcache (pte_t pte)
        set_bit(PG_arch_1, &page->flags);       /* mark page as clean */
 }
 
-#ifdef CONFIG_SWIOTLB
 /*
  * Since DMA is i-cache coherent, any (complete) pages that were written via
  * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
@@ -82,7 +82,6 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
                set_bit(PG_arch_1, &pfn_to_page(pfn)->flags);
        } while (++pfn <= PHYS_PFN(paddr + size - 1));
 }
-#endif
 
 inline void
 ia64_set_rbs_bot (void)
@@ -632,13 +631,17 @@ mem_init (void)
        BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE);
        BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE);
 
-#ifdef CONFIG_PCI
        /*
-        * This needs to be called _after_ the command line has been parsed but _before_
-        * any drivers that may need the PCI DMA interface are initialized or bootmem has
-        * been freed.
+        * This needs to be called _after_ the command line has been parsed but
+        * _before_ any drivers that may need the PCI DMA interface are
+        * initialized or bootmem has been freed.
         */
-       platform_dma_init();
+#ifdef CONFIG_INTEL_IOMMU
+       detect_intel_iommu();
+       if (!iommu_detected)
+#endif
+#ifdef CONFIG_SWIOTLB
+               swiotlb_init(1);
 #endif
 
 #ifdef CONFIG_FLATMEM
index 0714df1..72cc568 100644 (file)
@@ -245,7 +245,8 @@ resetsema:
        spinaphore_init(&ptcg_sem, max_purges);
 }
 
-void
+#ifdef CONFIG_SMP
+static void
 ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start,
                       unsigned long end, unsigned long nbits)
 {
@@ -282,6 +283,7 @@ ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start,
                 activate_context(active_mm);
         }
 }
+#endif /* CONFIG_SMP */
 
 void
 local_flush_tlb_all (void)
@@ -332,7 +334,7 @@ __flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
        preempt_disable();
 #ifdef CONFIG_SMP
        if (mm != current->active_mm || cpumask_weight(mm_cpumask(mm)) != 1) {
-               platform_global_tlb_purge(mm, start, end, nbits);
+               ia64_global_tlb_purge(mm, start, end, nbits);
                preempt_enable();
                return;
        }
index e1fa45b..acb55a4 100644 (file)
@@ -8,8 +8,7 @@
 #include <linux/init.h>
 #include <linux/vgaarb.h>
 #include <linux/screen_info.h>
-
-#include <asm/machvec.h>
+#include <asm/uv/uv.h>
 
 /*
  * Fixup to mark boot BIOS video selected by BIOS before it changes
@@ -35,8 +34,7 @@ static void pci_fixup_video(struct pci_dev *pdev)
        u16 config;
        struct resource *res;
 
-       if ((strcmp(ia64_platform_name, "dig") != 0)
-           && (strcmp(ia64_platform_name, "hpzx1")  != 0))
+       if (is_uv_system())
                return;
        /* Maybe, this machine supports legacy memory map. */
 
index 165e561..211757e 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/memblock.h>
 #include <linux/export.h>
 
-#include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/io.h>
 #include <asm/sal.h>
@@ -372,7 +371,6 @@ void pcibios_fixup_bus(struct pci_bus *b)
        }
        list_for_each_entry(dev, &b->devices, bus_list)
                pcibios_fixup_device_resources(dev);
-       platform_pci_fixup_bus(b);
 }
 
 void pcibios_add_bus(struct pci_bus *bus)
@@ -413,7 +411,7 @@ pcibios_disable_device (struct pci_dev *dev)
 }
 
 /**
- * ia64_pci_get_legacy_mem - generic legacy mem routine
+ * pci_get_legacy_mem - generic legacy mem routine
  * @bus: bus to get legacy memory base address for
  *
  * Find the base of legacy memory for @bus.  This is typically the first
@@ -424,7 +422,7 @@ pcibios_disable_device (struct pci_dev *dev)
  * This is the ia64 generic version of this routine.  Other platforms
  * are free to override it with a machine vector.
  */
-char *ia64_pci_get_legacy_mem(struct pci_bus *bus)
+char *pci_get_legacy_mem(struct pci_bus *bus)
 {
        return (char *)__IA64_UNCACHED_OFFSET;
 }
@@ -473,7 +471,7 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
 }
 
 /**
- * ia64_pci_legacy_read - read from legacy I/O space
+ * pci_legacy_read - read from legacy I/O space
  * @bus: bus to read
  * @port: legacy port value
  * @val: caller allocated storage for returned value
@@ -485,7 +483,7 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
  * overridden by the platform.  This is necessary on platforms that don't
  * support legacy I/O routing or that hard fail on legacy I/O timeouts.
  */
-int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
+int pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
 {
        int ret = size;
 
@@ -508,7 +506,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
 }
 
 /**
- * ia64_pci_legacy_write - perform a legacy I/O write
+ * pci_legacy_write - perform a legacy I/O write
  * @bus: bus pointer
  * @port: port to write
  * @val: value to write
@@ -516,7 +514,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
  *
  * Simply writes @size bytes of @val to @port.
  */
-int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
+int pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
 {
        int ret = size;
 
diff --git a/arch/ia64/sn/Makefile b/arch/ia64/sn/Makefile
deleted file mode 100644 (file)
index 79a7df0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# arch/ia64/sn/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 2004 Silicon Graphics, Inc.  All Rights Reserved.
-#
-# Makefile for the sn ia64 subplatform
-#
-
-obj-y += kernel/ pci/
diff --git a/arch/ia64/sn/include/ioerror.h b/arch/ia64/sn/include/ioerror.h
deleted file mode 100644 (file)
index e68f2b0..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_IOERROR_H
-#define _ASM_IA64_SN_IOERROR_H
-
-/*
- * IO error structure.
- *
- * This structure would expand to hold the information retrieved from
- * all IO related error registers.
- *
- * This structure is defined to hold all system specific
- * information related to a single error.
- *
- * This serves a couple of purpose.
- *      - Error handling often involves translating one form of address to other
- *        form. So, instead of having different data structures at each level,
- *        we have a single structure, and the appropriate fields get filled in
- *        at each layer.
- *      - This provides a way to dump all error related information in any layer
- *        of erorr handling (debugging aid).
- *
- * A second possibility is to allow each layer to define its own error
- * data structure, and fill in the proper fields. This has the advantage
- * of isolating the layers.
- * A big concern is the potential stack usage (and overflow), if each layer
- * defines these structures on stack (assuming we don't want to do kmalloc.
- *
- * Any layer wishing to pass extra information to a layer next to it in
- * error handling hierarchy, can do so as a separate parameter.
- */
-
-typedef struct io_error_s {
-    /* Bit fields indicating which structure fields are valid */
-    union {
-       struct {
-           unsigned                ievb_errortype:1;
-           unsigned                ievb_widgetnum:1;
-           unsigned                ievb_widgetdev:1;
-           unsigned                ievb_srccpu:1;
-           unsigned                ievb_srcnode:1;
-           unsigned                ievb_errnode:1;
-           unsigned                ievb_sysioaddr:1;
-           unsigned                ievb_xtalkaddr:1;
-           unsigned                ievb_busspace:1;
-           unsigned                ievb_busaddr:1;
-           unsigned                ievb_vaddr:1;
-           unsigned                ievb_memaddr:1;
-           unsigned                ievb_epc:1;
-           unsigned                ievb_ef:1;
-           unsigned                ievb_tnum:1;
-       } iev_b;
-       unsigned                iev_a;
-    } ie_v;
-
-    short                   ie_errortype;      /* error type: extra info about error */
-    short                   ie_widgetnum;      /* Widget number that's in error */
-    short                   ie_widgetdev;      /* Device within widget in error */
-    cpuid_t                 ie_srccpu; /* CPU on srcnode generating error */
-    cnodeid_t               ie_srcnode;                /* Node which caused the error   */
-    cnodeid_t               ie_errnode;                /* Node where error was noticed  */
-    iopaddr_t               ie_sysioaddr;      /* Sys specific IO address       */
-    iopaddr_t               ie_xtalkaddr;      /* Xtalk (48bit) addr of Error   */
-    iopaddr_t               ie_busspace;       /* Bus specific address space    */
-    iopaddr_t               ie_busaddr;                /* Bus specific address          */
-    caddr_t                 ie_vaddr;  /* Virtual address of error      */
-    iopaddr_t               ie_memaddr;                /* Physical memory address       */
-    caddr_t                ie_epc;             /* pc when error reported        */
-    caddr_t                ie_ef;              /* eframe when error reported    */
-    short                  ie_tnum;            /* Xtalk TNUM field */
-} ioerror_t;
-
-#define        IOERROR_INIT(e)         do { (e)->ie_v.iev_a = 0; } while (0)
-#define        IOERROR_SETVALUE(e,f,v) do { (e)->ie_ ## f = (v); (e)->ie_v.iev_b.ievb_ ## f = 1; } while (0)
-
-#endif /* _ASM_IA64_SN_IOERROR_H */
diff --git a/arch/ia64/sn/include/tio.h b/arch/ia64/sn/include/tio.h
deleted file mode 100644 (file)
index 6b2e7b7..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef _ASM_IA64_SN_TIO_H
-#define _ASM_IA64_SN_TIO_H
-
-#define        TIO_MMR_ADDR_MOD
-
-#define TIO_NODE_ID     TIO_MMR_ADDR_MOD(0x0000000090060e80)
-
-#define TIO_ITTE_BASE   0xb0008800        /* base of translation table entries */
-#define TIO_ITTE(bigwin)        (TIO_ITTE_BASE + 8*(bigwin))
-
-#define TIO_ITTE_OFFSET_BITS    8       /* size of offset field */
-#define TIO_ITTE_OFFSET_MASK    ((1<<TIO_ITTE_OFFSET_BITS)-1)
-#define TIO_ITTE_OFFSET_SHIFT   0
-
-#define TIO_ITTE_WIDGET_BITS    2       /* size of widget field */
-#define TIO_ITTE_WIDGET_MASK    ((1<<TIO_ITTE_WIDGET_BITS)-1)
-#define TIO_ITTE_WIDGET_SHIFT   12
-#define TIO_ITTE_VALID_MASK    0x1
-#define TIO_ITTE_VALID_SHIFT   16
-
-#define TIO_ITTE_WIDGET(itte) \
-       (((itte) >> TIO_ITTE_WIDGET_SHIFT) & TIO_ITTE_WIDGET_MASK)
-#define TIO_ITTE_VALID(itte) \
-       (((itte) >> TIO_ITTE_VALID_SHIFT) & TIO_ITTE_VALID_MASK)
-
-#define TIO_ITTE_PUT(nasid, bigwin, widget, addr, valid) \
-        REMOTE_HUB_S((nasid), TIO_ITTE(bigwin), \
-                (((((addr) >> TIO_BWIN_SIZE_BITS) & \
-                   TIO_ITTE_OFFSET_MASK) << TIO_ITTE_OFFSET_SHIFT) | \
-                (((widget) & TIO_ITTE_WIDGET_MASK) << TIO_ITTE_WIDGET_SHIFT)) | \
-               (( (valid) & TIO_ITTE_VALID_MASK) << TIO_ITTE_VALID_SHIFT))
-
-#endif /*  _ASM_IA64_SN_TIO_H */
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
deleted file mode 100644 (file)
index 8182583..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-#ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
-#define _ASM_IA64_SN_XTALK_HUBDEV_H
-
-#include "xtalk/xwidgetdev.h"
-
-#define HUB_WIDGET_ID_MAX 0xf
-#define DEV_PER_WIDGET (2*2*8)
-#define IIO_ITTE_WIDGET_BITS    4       /* size of widget field */
-#define IIO_ITTE_WIDGET_MASK    ((1<<IIO_ITTE_WIDGET_BITS)-1)
-#define IIO_ITTE_WIDGET_SHIFT   8
-
-#define IIO_ITTE_WIDGET(itte)  \
-       (((itte) >> IIO_ITTE_WIDGET_SHIFT) & IIO_ITTE_WIDGET_MASK)
-
-/*
- * Use the top big window as a surrogate for the first small window
- */
-#define SWIN0_BIGWIN            HUB_NUM_BIG_WINDOW
-#define IIO_NUM_ITTES   7
-#define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
-
-/* This struct is shared between the PROM and the kernel.
- * Changes to this struct will require corresponding changes to the kernel.
- */
-struct sn_flush_device_common {
-       int sfdl_bus;
-       int sfdl_slot;
-       int sfdl_pin;
-       struct common_bar_list {
-               unsigned long start;
-               unsigned long end;
-       } sfdl_bar_list[6];
-       unsigned long sfdl_force_int_addr;
-       unsigned long sfdl_flush_value;
-       volatile unsigned long *sfdl_flush_addr;
-       u32 sfdl_persistent_busnum;
-       u32 sfdl_persistent_segment;
-       struct pcibus_info *sfdl_pcibus_info;
-};
-
-/* This struct is kernel only and is not used by the PROM */
-struct sn_flush_device_kernel {
-       spinlock_t sfdl_flush_lock;
-       struct sn_flush_device_common *common;
-};
-
-/* 01/16/06 This struct is the old PROM/kernel struct and needs to be included
- * for older official PROMs to function on the new kernel base.  This struct
- * will be removed when the next official PROM release occurs. */
-
-struct sn_flush_device_war {
-       struct sn_flush_device_common common;
-       u32 filler; /* older PROMs expect the default size of a spinlock_t */
-};
-
-/*
- * **widget_p - Used as an array[wid_num][device] of sn_flush_device_kernel.
- */
-struct sn_flush_nasid_entry  {
-       struct sn_flush_device_kernel **widget_p; // Used as an array of wid_num
-       u64 iio_itte[8];
-};
-
-struct hubdev_info {
-       geoid_t                         hdi_geoid;
-       short                           hdi_nasid;
-       short                           hdi_peer_nasid;   /* Dual Porting Peer */
-
-       struct sn_flush_nasid_entry     hdi_flush_nasid_list;
-       struct xwidget_info             hdi_xwidget_info[HUB_WIDGET_ID_MAX + 1];
-
-
-       void                            *hdi_nodepda;
-       void                            *hdi_node_vertex;
-       u32                             max_segment_number;
-       u32                             max_pcibus_number;
-};
-
-extern void hubdev_init_node(nodepda_t *, cnodeid_t);
-extern void hub_error_init(struct hubdev_info *);
-extern void ice_error_init(struct hubdev_info *);
-
-
-#endif /* _ASM_IA64_SN_XTALK_HUBDEV_H */
diff --git a/arch/ia64/sn/include/xtalk/xbow.h b/arch/ia64/sn/include/xtalk/xbow.h
deleted file mode 100644 (file)
index 90f37a4..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992-1997,2000-2006 Silicon Graphics, Inc. All Rights
- * Reserved.
- */
-#ifndef _ASM_IA64_SN_XTALK_XBOW_H
-#define _ASM_IA64_SN_XTALK_XBOW_H
-
-#define XBOW_PORT_8    0x8
-#define XBOW_PORT_C    0xc
-#define XBOW_PORT_F    0xf
-
-#define MAX_XBOW_PORTS 8       /* number of ports on xbow chip */
-#define BASE_XBOW_PORT XBOW_PORT_8     /* Lowest external port */
-
-#define        XBOW_CREDIT     4
-
-#define MAX_XBOW_NAME  16
-
-/* Register set for each xbow link */
-typedef volatile struct xb_linkregs_s {
-/*
- * we access these through synergy unswizzled space, so the address
- * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.)
- * That's why we put the register first and filler second.
- */
-       u32 link_ibf;
-       u32 filler0;    /* filler for proper alignment */
-       u32 link_control;
-       u32 filler1;
-       u32 link_status;
-       u32 filler2;
-       u32 link_arb_upper;
-       u32 filler3;
-       u32 link_arb_lower;
-       u32 filler4;
-       u32 link_status_clr;
-       u32 filler5;
-       u32 link_reset;
-       u32 filler6;
-       u32 link_aux_status;
-       u32 filler7;
-} xb_linkregs_t;
-
-typedef volatile struct xbow_s {
-       /* standard widget configuration 0x000000-0x000057 */
-       struct widget_cfg xb_widget;  /* 0x000000 */
-
-       /* helper fieldnames for accessing bridge widget */
-
-#define xb_wid_id              xb_widget.w_id
-#define xb_wid_stat            xb_widget.w_status
-#define xb_wid_err_upper       xb_widget.w_err_upper_addr
-#define xb_wid_err_lower       xb_widget.w_err_lower_addr
-#define xb_wid_control         xb_widget.w_control
-#define xb_wid_req_timeout     xb_widget.w_req_timeout
-#define xb_wid_int_upper       xb_widget.w_intdest_upper_addr
-#define xb_wid_int_lower       xb_widget.w_intdest_lower_addr
-#define xb_wid_err_cmdword     xb_widget.w_err_cmd_word
-#define xb_wid_llp             xb_widget.w_llp_cfg
-#define xb_wid_stat_clr        xb_widget.w_tflush
-
-/*
- * we access these through synergy unswizzled space, so the address
- * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.)
- * That's why we put the register first and filler second.
- */
-       /* xbow-specific widget configuration    0x000058-0x0000FF */
-       u32 xb_wid_arb_reload; /* 0x00005C */
-       u32 _pad_000058;
-       u32 xb_perf_ctr_a;      /* 0x000064 */
-       u32 _pad_000060;
-       u32 xb_perf_ctr_b;      /* 0x00006c */
-       u32 _pad_000068;
-       u32 xb_nic;             /* 0x000074 */
-       u32 _pad_000070;
-
-       /* Xbridge only */
-       u32 xb_w0_rst_fnc;      /* 0x00007C */
-       u32 _pad_000078;
-       u32 xb_l8_rst_fnc;      /* 0x000084 */
-       u32 _pad_000080;
-       u32 xb_l9_rst_fnc;      /* 0x00008c */
-       u32 _pad_000088;
-       u32 xb_la_rst_fnc;      /* 0x000094 */
-       u32 _pad_000090;
-       u32 xb_lb_rst_fnc;      /* 0x00009c */
-       u32 _pad_000098;
-       u32 xb_lc_rst_fnc;      /* 0x0000a4 */
-       u32 _pad_0000a0;
-       u32 xb_ld_rst_fnc;      /* 0x0000ac */
-       u32 _pad_0000a8;
-       u32 xb_le_rst_fnc;      /* 0x0000b4 */
-       u32 _pad_0000b0;
-       u32 xb_lf_rst_fnc;      /* 0x0000bc */
-       u32 _pad_0000b8;
-       u32 xb_lock;            /* 0x0000c4 */
-       u32 _pad_0000c0;
-       u32 xb_lock_clr;        /* 0x0000cc */
-       u32 _pad_0000c8;
-       /* end of Xbridge only */
-       u32 _pad_0000d0[12];
-
-       /* Link Specific Registers, port 8..15   0x000100-0x000300 */
-       xb_linkregs_t xb_link_raw[MAX_XBOW_PORTS];
-} xbow_t;
-
-#define xb_link(p) xb_link_raw[(p) & (MAX_XBOW_PORTS - 1)]
-
-#define XB_FLAGS_EXISTS                0x1     /* device exists */
-#define XB_FLAGS_MASTER                0x2
-#define XB_FLAGS_SLAVE         0x0
-#define XB_FLAGS_GBR           0x4
-#define XB_FLAGS_16BIT         0x8
-#define XB_FLAGS_8BIT          0x0
-
-/* is widget port number valid?  (based on version 7.0 of xbow spec) */
-#define XBOW_WIDGET_IS_VALID(wid) ((wid) >= XBOW_PORT_8 && (wid) <= XBOW_PORT_F)
-
-/* whether to use upper or lower arbitration register, given source widget id */
-#define XBOW_ARB_IS_UPPER(wid)         ((wid) >= XBOW_PORT_8 && (wid) <= XBOW_PORT_B)
-#define XBOW_ARB_IS_LOWER(wid)         ((wid) >= XBOW_PORT_C && (wid) <= XBOW_PORT_F)
-
-/* offset of arbitration register, given source widget id */
-#define XBOW_ARB_OFF(wid)      (XBOW_ARB_IS_UPPER(wid) ? 0x1c : 0x24)
-
-#define        XBOW_WID_ID             WIDGET_ID
-#define        XBOW_WID_STAT           WIDGET_STATUS
-#define        XBOW_WID_ERR_UPPER      WIDGET_ERR_UPPER_ADDR
-#define        XBOW_WID_ERR_LOWER      WIDGET_ERR_LOWER_ADDR
-#define        XBOW_WID_CONTROL        WIDGET_CONTROL
-#define        XBOW_WID_REQ_TO         WIDGET_REQ_TIMEOUT
-#define        XBOW_WID_INT_UPPER      WIDGET_INTDEST_UPPER_ADDR
-#define        XBOW_WID_INT_LOWER      WIDGET_INTDEST_LOWER_ADDR
-#define        XBOW_WID_ERR_CMDWORD    WIDGET_ERR_CMD_WORD
-#define        XBOW_WID_LLP            WIDGET_LLP_CFG
-#define        XBOW_WID_STAT_CLR       WIDGET_TFLUSH
-#define XBOW_WID_ARB_RELOAD    0x5c
-#define XBOW_WID_PERF_CTR_A    0x64
-#define XBOW_WID_PERF_CTR_B    0x6c
-#define XBOW_WID_NIC           0x74
-
-/* Xbridge only */
-#define XBOW_W0_RST_FNC                0x00007C
-#define        XBOW_L8_RST_FNC         0x000084
-#define        XBOW_L9_RST_FNC         0x00008c
-#define        XBOW_LA_RST_FNC         0x000094
-#define        XBOW_LB_RST_FNC         0x00009c
-#define        XBOW_LC_RST_FNC         0x0000a4
-#define        XBOW_LD_RST_FNC         0x0000ac
-#define        XBOW_LE_RST_FNC         0x0000b4
-#define        XBOW_LF_RST_FNC         0x0000bc
-#define XBOW_RESET_FENCE(x) ((x) > 7 && (x) < 16) ? \
-                               (XBOW_W0_RST_FNC + ((x) - 7) * 8) : \
-                               ((x) == 0) ? XBOW_W0_RST_FNC : 0
-#define XBOW_LOCK              0x0000c4
-#define XBOW_LOCK_CLR          0x0000cc
-/* End of Xbridge only */
-
-/* used only in ide, but defined here within the reserved portion */
-/* of the widget0 address space (before 0xf4) */
-#define        XBOW_WID_UNDEF          0xe4
-
-/* xbow link register set base, legal value for x is 0x8..0xf */
-#define        XB_LINK_BASE            0x100
-#define        XB_LINK_OFFSET          0x40
-#define        XB_LINK_REG_BASE(x)     (XB_LINK_BASE + ((x) & (MAX_XBOW_PORTS - 1)) * XB_LINK_OFFSET)
-
-#define        XB_LINK_IBUF_FLUSH(x)   (XB_LINK_REG_BASE(x) + 0x4)
-#define        XB_LINK_CTRL(x)         (XB_LINK_REG_BASE(x) + 0xc)
-#define        XB_LINK_STATUS(x)       (XB_LINK_REG_BASE(x) + 0x14)
-#define        XB_LINK_ARB_UPPER(x)    (XB_LINK_REG_BASE(x) + 0x1c)
-#define        XB_LINK_ARB_LOWER(x)    (XB_LINK_REG_BASE(x) + 0x24)
-#define        XB_LINK_STATUS_CLR(x)   (XB_LINK_REG_BASE(x) + 0x2c)
-#define        XB_LINK_RESET(x)        (XB_LINK_REG_BASE(x) + 0x34)
-#define        XB_LINK_AUX_STATUS(x)   (XB_LINK_REG_BASE(x) + 0x3c)
-
-/* link_control(x) */
-#define        XB_CTRL_LINKALIVE_IE            0x80000000      /* link comes alive */
-/* reserved:                   0x40000000 */
-#define        XB_CTRL_PERF_CTR_MODE_MSK       0x30000000      /* perf counter mode */
-#define        XB_CTRL_IBUF_LEVEL_MSK          0x0e000000      /* input packet buffer
-                                                          level */
-#define        XB_CTRL_8BIT_MODE               0x01000000      /* force link into 8
-                                                          bit mode */
-#define XB_CTRL_BAD_LLP_PKT            0x00800000      /* force bad LLP
-                                                          packet */
-#define XB_CTRL_WIDGET_CR_MSK          0x007c0000      /* LLP widget credit
-                                                          mask */
-#define XB_CTRL_WIDGET_CR_SHFT 18                      /* LLP widget credit
-                                                          shift */
-#define XB_CTRL_ILLEGAL_DST_IE         0x00020000      /* illegal destination
-                                                        */
-#define XB_CTRL_OALLOC_IBUF_IE         0x00010000      /* overallocated input
-                                                          buffer */
-/* reserved:                   0x0000fe00 */
-#define XB_CTRL_BNDWDTH_ALLOC_IE       0x00000100      /* bandwidth alloc */
-#define XB_CTRL_RCV_CNT_OFLOW_IE       0x00000080      /* rcv retry overflow */
-#define XB_CTRL_XMT_CNT_OFLOW_IE       0x00000040      /* xmt retry overflow */
-#define XB_CTRL_XMT_MAX_RTRY_IE                0x00000020      /* max transmit retry */
-#define XB_CTRL_RCV_IE                 0x00000010      /* receive */
-#define XB_CTRL_XMT_RTRY_IE            0x00000008      /* transmit retry */
-/* reserved:                   0x00000004 */
-#define        XB_CTRL_MAXREQ_TOUT_IE          0x00000002      /* maximum request
-                                                          timeout */
-#define        XB_CTRL_SRC_TOUT_IE             0x00000001      /* source timeout */
-
-/* link_status(x) */
-#define        XB_STAT_LINKALIVE               XB_CTRL_LINKALIVE_IE
-/* reserved:                   0x7ff80000 */
-#define        XB_STAT_MULTI_ERR               0x00040000      /* multi error */
-#define        XB_STAT_ILLEGAL_DST_ERR         XB_CTRL_ILLEGAL_DST_IE
-#define        XB_STAT_OALLOC_IBUF_ERR         XB_CTRL_OALLOC_IBUF_IE
-#define        XB_STAT_BNDWDTH_ALLOC_ID_MSK    0x0000ff00      /* port bitmask */
-#define        XB_STAT_RCV_CNT_OFLOW_ERR       XB_CTRL_RCV_CNT_OFLOW_IE
-#define        XB_STAT_XMT_CNT_OFLOW_ERR       XB_CTRL_XMT_CNT_OFLOW_IE
-#define        XB_STAT_XMT_MAX_RTRY_ERR        XB_CTRL_XMT_MAX_RTRY_IE
-#define        XB_STAT_RCV_ERR                 XB_CTRL_RCV_IE
-#define        XB_STAT_XMT_RTRY_ERR            XB_CTRL_XMT_RTRY_IE
-/* reserved:                   0x00000004 */
-#define        XB_STAT_MAXREQ_TOUT_ERR         XB_CTRL_MAXREQ_TOUT_IE
-#define        XB_STAT_SRC_TOUT_ERR            XB_CTRL_SRC_TOUT_IE
-
-/* link_aux_status(x) */
-#define        XB_AUX_STAT_RCV_CNT     0xff000000
-#define        XB_AUX_STAT_XMT_CNT     0x00ff0000
-#define        XB_AUX_STAT_TOUT_DST    0x0000ff00
-#define        XB_AUX_LINKFAIL_RST_BAD 0x00000040
-#define        XB_AUX_STAT_PRESENT     0x00000020
-#define        XB_AUX_STAT_PORT_WIDTH  0x00000010
-/*     reserved:               0x0000000f */
-
-/*
- * link_arb_upper/link_arb_lower(x), (reg) should be the link_arb_upper
- * register if (x) is 0x8..0xb, link_arb_lower if (x) is 0xc..0xf
- */
-#define        XB_ARB_GBR_MSK          0x1f
-#define        XB_ARB_RR_MSK           0x7
-#define        XB_ARB_GBR_SHFT(x)      (((x) & 0x3) * 8)
-#define        XB_ARB_RR_SHFT(x)       (((x) & 0x3) * 8 + 5)
-#define        XB_ARB_GBR_CNT(reg,x)   ((reg) >> XB_ARB_GBR_SHFT(x) & XB_ARB_GBR_MSK)
-#define        XB_ARB_RR_CNT(reg,x)    ((reg) >> XB_ARB_RR_SHFT(x) & XB_ARB_RR_MSK)
-
-/* XBOW_WID_STAT */
-#define        XB_WID_STAT_LINK_INTR_SHFT      (24)
-#define        XB_WID_STAT_LINK_INTR_MASK      (0xFF << XB_WID_STAT_LINK_INTR_SHFT)
-#define        XB_WID_STAT_LINK_INTR(x) \
-       (0x1 << (((x)&7) + XB_WID_STAT_LINK_INTR_SHFT))
-#define        XB_WID_STAT_WIDGET0_INTR        0x00800000
-#define XB_WID_STAT_SRCID_MASK         0x000003c0      /* Xbridge only */
-#define        XB_WID_STAT_REG_ACC_ERR         0x00000020
-#define XB_WID_STAT_RECV_TOUT          0x00000010      /* Xbridge only */
-#define XB_WID_STAT_ARB_TOUT           0x00000008      /* Xbridge only */
-#define        XB_WID_STAT_XTALK_ERR           0x00000004
-#define XB_WID_STAT_DST_TOUT           0x00000002      /* Xbridge only */
-#define        XB_WID_STAT_MULTI_ERR           0x00000001
-
-#define XB_WID_STAT_SRCID_SHFT         6
-
-/* XBOW_WID_CONTROL */
-#define XB_WID_CTRL_REG_ACC_IE         XB_WID_STAT_REG_ACC_ERR
-#define XB_WID_CTRL_RECV_TOUT          XB_WID_STAT_RECV_TOUT
-#define XB_WID_CTRL_ARB_TOUT           XB_WID_STAT_ARB_TOUT
-#define XB_WID_CTRL_XTALK_IE           XB_WID_STAT_XTALK_ERR
-
-/* XBOW_WID_INT_UPPER */
-/* defined in xwidget.h for WIDGET_INTDEST_UPPER_ADDR */
-
-/* XBOW WIDGET part number, in the ID register */
-#define XBOW_WIDGET_PART_NUM   0x0             /* crossbow */
-#define XXBOW_WIDGET_PART_NUM  0xd000          /* Xbridge */
-#define        XBOW_WIDGET_MFGR_NUM    0x0
-#define        XXBOW_WIDGET_MFGR_NUM   0x0
-#define PXBOW_WIDGET_PART_NUM   0xd100         /* PIC */
-
-#define        XBOW_REV_1_0            0x1     /* xbow rev 1.0 is "1" */
-#define        XBOW_REV_1_1            0x2     /* xbow rev 1.1 is "2" */
-#define XBOW_REV_1_2           0x3     /* xbow rev 1.2 is "3" */
-#define XBOW_REV_1_3           0x4     /* xbow rev 1.3 is "4" */
-#define XBOW_REV_2_0           0x5     /* xbow rev 2.0 is "5" */
-
-#define XXBOW_PART_REV_1_0             (XXBOW_WIDGET_PART_NUM << 4 | 0x1 )
-#define XXBOW_PART_REV_2_0             (XXBOW_WIDGET_PART_NUM << 4 | 0x2 )
-
-/* XBOW_WID_ARB_RELOAD */
-#define        XBOW_WID_ARB_RELOAD_INT 0x3f    /* GBR reload interval */
-
-#define IS_XBRIDGE_XBOW(wid) \
-       (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \
-       XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM)
-
-#define IS_PIC_XBOW(wid) \
-       (XWIDGET_PART_NUM(wid) == PXBOW_WIDGET_PART_NUM && \
-       XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM)
-
-#define XBOW_WAR_ENABLED(pv, widid) ((1 << XWIDGET_REV_NUM(widid)) & pv)
-
-#endif /* _ASM_IA64_SN_XTALK_XBOW_H */
diff --git a/arch/ia64/sn/include/xtalk/xwidgetdev.h b/arch/ia64/sn/include/xtalk/xwidgetdev.h
deleted file mode 100644 (file)
index 2800eda..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved.
- */
-#ifndef _ASM_IA64_SN_XTALK_XWIDGET_H
-#define _ASM_IA64_SN_XTALK_XWIDGET_H
-
-/* WIDGET_ID */
-#define WIDGET_REV_NUM                  0xf0000000
-#define WIDGET_PART_NUM                 0x0ffff000
-#define WIDGET_MFG_NUM                  0x00000ffe
-#define WIDGET_REV_NUM_SHFT             28
-#define WIDGET_PART_NUM_SHFT            12
-#define WIDGET_MFG_NUM_SHFT             1
-
-#define XWIDGET_PART_NUM(widgetid) (((widgetid) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT)
-#define XWIDGET_REV_NUM(widgetid) (((widgetid) & WIDGET_REV_NUM) >> WIDGET_REV_NUM_SHFT)
-#define XWIDGET_MFG_NUM(widgetid) (((widgetid) & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT)
-#define XWIDGET_PART_REV_NUM(widgetid) ((XWIDGET_PART_NUM(widgetid) << 4) | \
-                                        XWIDGET_REV_NUM(widgetid))
-#define XWIDGET_PART_REV_NUM_REV(partrev) (partrev & 0xf)
-
-/* widget configuration registers */
-struct widget_cfg{
-       u32     w_id;   /* 0x04 */
-       u32     w_pad_0;        /* 0x00 */
-       u32     w_status;       /* 0x0c */
-       u32     w_pad_1;        /* 0x08 */
-       u32     w_err_upper_addr;       /* 0x14 */
-       u32     w_pad_2;        /* 0x10 */
-       u32     w_err_lower_addr;       /* 0x1c */
-       u32     w_pad_3;        /* 0x18 */
-       u32     w_control;      /* 0x24 */
-       u32     w_pad_4;        /* 0x20 */
-       u32     w_req_timeout;  /* 0x2c */
-       u32     w_pad_5;        /* 0x28 */
-       u32     w_intdest_upper_addr;   /* 0x34 */
-       u32     w_pad_6;        /* 0x30 */
-       u32     w_intdest_lower_addr;   /* 0x3c */
-       u32     w_pad_7;        /* 0x38 */
-       u32     w_err_cmd_word; /* 0x44 */
-       u32     w_pad_8;        /* 0x40 */
-       u32     w_llp_cfg;      /* 0x4c */
-       u32     w_pad_9;        /* 0x48 */
-       u32     w_tflush;       /* 0x54 */
-       u32     w_pad_10;       /* 0x50 */
-};
-
-/*
- * Crosstalk Widget Hardware Identification, as defined in the Crosstalk spec.
- */
-struct xwidget_hwid{
-       int             mfg_num;
-       int             rev_num;
-       int             part_num;
-};
-
-struct xwidget_info{
-
-       struct xwidget_hwid     xwi_hwid;       /* Widget Identification */
-       char                    xwi_masterxid;  /* Hub's Widget Port Number */
-       void                    *xwi_hubinfo;     /* Hub's provider private info */
-       u64                     *xwi_hub_provider; /* prom provider functions */
-       void                    *xwi_vertex;
-};
-
-#endif                          /* _ASM_IA64_SN_XTALK_XWIDGET_H */
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
deleted file mode 100644 (file)
index 9c349dd..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# arch/ia64/sn/kernel/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1999,2001-2006,2008 Silicon Graphics, Inc.  All Rights Reserved.
-#
-
-ccflags-y := -I $(srctree)/arch/ia64/sn/include
-
-obj-y                          += setup.o bte.o bte_error.o irq.o mca.o idle.o \
-                                  huberror.o io_acpi_init.o io_common.o \
-                                  io_init.o iomv.o klconflib.o pio_phys.o \
-                                  sn2/
-obj-$(CONFIG_IA64_GENERIC)      += machvec.o
-obj-$(CONFIG_SGI_TIOCX)                += tiocx.o
-obj-$(CONFIG_PCI_MSI)          += msi_sn.o
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
deleted file mode 100644 (file)
index 9900e6d..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000-2007 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/module.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/shubio.h>
-#include <asm/nodedata.h>
-#include <asm/delay.h>
-
-#include <linux/memblock.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <asm/sn/bte.h>
-
-#ifndef L1_CACHE_MASK
-#define L1_CACHE_MASK (L1_CACHE_BYTES - 1)
-#endif
-
-/* two interfaces on two btes */
-#define MAX_INTERFACES_TO_TRY          4
-#define MAX_NODES_TO_TRY               2
-
-static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface)
-{
-       nodepda_t *tmp_nodepda;
-
-       if (nasid_to_cnodeid(nasid) == -1)
-               return (struct bteinfo_s *)NULL;
-
-       tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid));
-       return &tmp_nodepda->bte_if[interface];
-
-}
-
-static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode)
-{
-       if (is_shub2()) {
-               BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24)));
-       } else {
-               BTE_LNSTAT_STORE(bte, len);
-               BTE_CTRL_STORE(bte, mode);
-       }
-}
-
-/************************************************************************
- * Block Transfer Engine copy related functions.
- *
- ***********************************************************************/
-
-/*
- * bte_copy(src, dest, len, mode, notification)
- *
- * Use the block transfer engine to move kernel memory from src to dest
- * using the assigned mode.
- *
- * Parameters:
- *   src - physical address of the transfer source.
- *   dest - physical address of the transfer destination.
- *   len - number of bytes to transfer from source to dest.
- *   mode - hardware defined.  See reference information
- *          for IBCT0/1 in the SHUB Programmers Reference
- *   notification - kernel virtual address of the notification cache
- *                  line.  If NULL, the default is used and
- *                  the bte_copy is synchronous.
- *
- * NOTE:  This function requires src, dest, and len to
- * be cacheline aligned.
- */
-bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
-{
-       u64 transfer_size;
-       u64 transfer_stat;
-       u64 notif_phys_addr;
-       struct bteinfo_s *bte;
-       bte_result_t bte_status;
-       unsigned long irq_flags;
-       unsigned long itc_end = 0;
-       int nasid_to_try[MAX_NODES_TO_TRY];
-       int my_nasid = cpuid_to_nasid(raw_smp_processor_id());
-       int bte_if_index, nasid_index;
-       int bte_first, btes_per_node = BTES_PER_NODE;
-
-       BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n",
-                   src, dest, len, mode, notification));
-
-       if (len == 0) {
-               return BTE_SUCCESS;
-       }
-
-       BUG_ON(len & L1_CACHE_MASK);
-       BUG_ON(src & L1_CACHE_MASK);
-       BUG_ON(dest & L1_CACHE_MASK);
-       BUG_ON(len > BTE_MAX_XFER);
-
-       /*
-        * Start with interface corresponding to cpu number
-        */
-       bte_first = raw_smp_processor_id() % btes_per_node;
-
-       if (mode & BTE_USE_DEST) {
-               /* try remote then local */
-               nasid_to_try[0] = NASID_GET(dest);
-               if (mode & BTE_USE_ANY) {
-                       nasid_to_try[1] = my_nasid;
-               } else {
-                       nasid_to_try[1] = 0;
-               }
-       } else {
-               /* try local then remote */
-               nasid_to_try[0] = my_nasid;
-               if (mode & BTE_USE_ANY) {
-                       nasid_to_try[1] = NASID_GET(dest);
-               } else {
-                       nasid_to_try[1] = 0;
-               }
-       }
-
-retry_bteop:
-       do {
-               local_irq_save(irq_flags);
-
-               bte_if_index = bte_first;
-               nasid_index = 0;
-
-               /* Attempt to lock one of the BTE interfaces. */
-               while (nasid_index < MAX_NODES_TO_TRY) {
-                       bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index);
-
-                       if (bte == NULL) {
-                               nasid_index++;
-                               continue;
-                       }
-
-                       if (spin_trylock(&bte->spinlock)) {
-                               if (!(*bte->most_rcnt_na & BTE_WORD_AVAILABLE) ||
-                                   (BTE_LNSTAT_LOAD(bte) & BTE_ACTIVE)) {
-                                       /* Got the lock but BTE still busy */
-                                       spin_unlock(&bte->spinlock);
-                               } else {
-                                       /* we got the lock and it's not busy */
-                                       break;
-                               }
-                       }
-
-                       bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */
-                       if (bte_if_index == bte_first) {
-                               /*
-                                * We've tried all interfaces on this node
-                                */
-                               nasid_index++;
-                       }
-
-                       bte = NULL;
-               }
-
-               if (bte != NULL) {
-                       break;
-               }
-
-               local_irq_restore(irq_flags);
-
-               if (!(mode & BTE_WACQUIRE)) {
-                       return BTEFAIL_NOTAVAIL;
-               }
-       } while (1);
-
-       if (notification == NULL) {
-               /* User does not want to be notified. */
-               bte->most_rcnt_na = &bte->notify;
-       } else {
-               bte->most_rcnt_na = notification;
-       }
-
-       /* Calculate the number of cache lines to transfer. */
-       transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);
-
-       /* Initialize the notification to a known value. */
-       *bte->most_rcnt_na = BTE_WORD_BUSY;
-       notif_phys_addr = (u64)bte->most_rcnt_na;
-
-       /* Set the source and destination registers */
-       BTE_PRINTKV(("IBSA = 0x%lx)\n", src));
-       BTE_SRC_STORE(bte, src);
-       BTE_PRINTKV(("IBDA = 0x%lx)\n", dest));
-       BTE_DEST_STORE(bte, dest);
-
-       /* Set the notification register */
-       BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr));
-       BTE_NOTIF_STORE(bte, notif_phys_addr);
-
-       /* Initiate the transfer */
-       BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode)));
-       bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode));
-
-       itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec);
-
-       spin_unlock_irqrestore(&bte->spinlock, irq_flags);
-
-       if (notification != NULL) {
-               return BTE_SUCCESS;
-       }
-
-       while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) {
-               cpu_relax();
-               if (ia64_get_itc() > itc_end) {
-                       BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n",
-                               NASID_GET(bte->bte_base_addr), bte->bte_num,
-                               BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na) );
-                       bte->bte_error_count++;
-                       bte->bh_error = IBLS_ERROR;
-                       bte_error_handler(NODEPDA(bte->bte_cnode));
-                       *bte->most_rcnt_na = BTE_WORD_AVAILABLE;
-                       goto retry_bteop;
-               }
-       }
-
-       BTE_PRINTKV((" Delay Done.  IBLS = 0x%lx, most_rcnt_na = 0x%lx\n",
-                    BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na));
-
-       if (transfer_stat & IBLS_ERROR) {
-               bte_status = BTE_GET_ERROR_STATUS(transfer_stat);
-       } else {
-               bte_status = BTE_SUCCESS;
-       }
-       *bte->most_rcnt_na = BTE_WORD_AVAILABLE;
-
-       BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n",
-                   BTE_LNSTAT_LOAD(bte), *bte->most_rcnt_na));
-
-       return bte_status;
-}
-
-EXPORT_SYMBOL(bte_copy);
-
-/*
- * bte_unaligned_copy(src, dest, len, mode)
- *
- * use the block transfer engine to move kernel
- * memory from src to dest using the assigned mode.
- *
- * Parameters:
- *   src - physical address of the transfer source.
- *   dest - physical address of the transfer destination.
- *   len - number of bytes to transfer from source to dest.
- *   mode - hardware defined.  See reference information
- *          for IBCT0/1 in the SGI documentation.
- *
- * NOTE: If the source, dest, and len are all cache line aligned,
- * then it would be _FAR_ preferable to use bte_copy instead.
- */
-bte_result_t bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode)
-{
-       int destFirstCacheOffset;
-       u64 headBteSource;
-       u64 headBteLen;
-       u64 headBcopySrcOffset;
-       u64 headBcopyDest;
-       u64 headBcopyLen;
-       u64 footBteSource;
-       u64 footBteLen;
-       u64 footBcopyDest;
-       u64 footBcopyLen;
-       bte_result_t rv;
-       char *bteBlock, *bteBlock_unaligned;
-
-       if (len == 0) {
-               return BTE_SUCCESS;
-       }
-
-       /* temporary buffer used during unaligned transfers */
-       bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES, GFP_KERNEL);
-       if (bteBlock_unaligned == NULL) {
-               return BTEFAIL_NOTAVAIL;
-       }
-       bteBlock = (char *)L1_CACHE_ALIGN((u64) bteBlock_unaligned);
-
-       headBcopySrcOffset = src & L1_CACHE_MASK;
-       destFirstCacheOffset = dest & L1_CACHE_MASK;
-
-       /*
-        * At this point, the transfer is broken into
-        * (up to) three sections.  The first section is
-        * from the start address to the first physical
-        * cache line, the second is from the first physical
-        * cache line to the last complete cache line,
-        * and the third is from the last cache line to the
-        * end of the buffer.  The first and third sections
-        * are handled by bte copying into a temporary buffer
-        * and then bcopy'ing the necessary section into the
-        * final location.  The middle section is handled with
-        * a standard bte copy.
-        *
-        * One nasty exception to the above rule is when the
-        * source and destination are not symmetrically
-        * mis-aligned.  If the source offset from the first
-        * cache line is different from the destination offset,
-        * we make the first section be the entire transfer
-        * and the bcopy the entire block into place.
-        */
-       if (headBcopySrcOffset == destFirstCacheOffset) {
-
-               /*
-                * Both the source and destination are the same
-                * distance from a cache line boundary so we can
-                * use the bte to transfer the bulk of the
-                * data.
-                */
-               headBteSource = src & ~L1_CACHE_MASK;
-               headBcopyDest = dest;
-               if (headBcopySrcOffset) {
-                       headBcopyLen =
-                           (len >
-                            (L1_CACHE_BYTES -
-                             headBcopySrcOffset) ? L1_CACHE_BYTES
-                            - headBcopySrcOffset : len);
-                       headBteLen = L1_CACHE_BYTES;
-               } else {
-                       headBcopyLen = 0;
-                       headBteLen = 0;
-               }
-
-               if (len > headBcopyLen) {
-                       footBcopyLen = (len - headBcopyLen) & L1_CACHE_MASK;
-                       footBteLen = L1_CACHE_BYTES;
-
-                       footBteSource = src + len - footBcopyLen;
-                       footBcopyDest = dest + len - footBcopyLen;
-
-                       if (footBcopyDest == (headBcopyDest + headBcopyLen)) {
-                               /*
-                                * We have two contiguous bcopy
-                                * blocks.  Merge them.
-                                */
-                               headBcopyLen += footBcopyLen;
-                               headBteLen += footBteLen;
-                       } else if (footBcopyLen > 0) {
-                               rv = bte_copy(footBteSource,
-                                             ia64_tpa((unsigned long)bteBlock),
-                                             footBteLen, mode, NULL);
-                               if (rv != BTE_SUCCESS) {
-                                       kfree(bteBlock_unaligned);
-                                       return rv;
-                               }
-
-                               memcpy(__va(footBcopyDest),
-                                      (char *)bteBlock, footBcopyLen);
-                       }
-               } else {
-                       footBcopyLen = 0;
-                       footBteLen = 0;
-               }
-
-               if (len > (headBcopyLen + footBcopyLen)) {
-                       /* now transfer the middle. */
-                       rv = bte_copy((src + headBcopyLen),
-                                     (dest +
-                                      headBcopyLen),
-                                     (len - headBcopyLen -
-                                      footBcopyLen), mode, NULL);
-                       if (rv != BTE_SUCCESS) {
-                               kfree(bteBlock_unaligned);
-                               return rv;
-                       }
-
-               }
-       } else {
-
-               /*
-                * The transfer is not symmetric, we will
-                * allocate a buffer large enough for all the
-                * data, bte_copy into that buffer and then
-                * bcopy to the destination.
-                */
-
-               headBcopySrcOffset = src & L1_CACHE_MASK;
-               headBcopyDest = dest;
-               headBcopyLen = len;
-
-               headBteSource = src - headBcopySrcOffset;
-               /* Add the leading and trailing bytes from source */
-               headBteLen = L1_CACHE_ALIGN(len + headBcopySrcOffset);
-       }
-
-       if (headBcopyLen > 0) {
-               rv = bte_copy(headBteSource,
-                             ia64_tpa((unsigned long)bteBlock), headBteLen,
-                             mode, NULL);
-               if (rv != BTE_SUCCESS) {
-                       kfree(bteBlock_unaligned);
-                       return rv;
-               }
-
-               memcpy(__va(headBcopyDest), ((char *)bteBlock +
-                                            headBcopySrcOffset), headBcopyLen);
-       }
-       kfree(bteBlock_unaligned);
-       return BTE_SUCCESS;
-}
-
-EXPORT_SYMBOL(bte_unaligned_copy);
-
-/************************************************************************
- * Block Transfer Engine initialization functions.
- *
- ***********************************************************************/
-static void bte_recovery_timeout(struct timer_list *t)
-{
-       struct nodepda_s *nodepda = from_timer(nodepda, t, bte_recovery_timer);
-
-       bte_error_handler(nodepda);
-}
-
-/*
- * bte_init_node(nodepda, cnode)
- *
- * Initialize the nodepda structure with BTE base addresses and
- * spinlocks.
- */
-void bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
-{
-       int i;
-
-       /*
-        * Indicate that all the block transfer engines on this node
-        * are available.
-        */
-
-       /*
-        * Allocate one bte_recover_t structure per node.  It holds
-        * the recovery lock for node.  All the bte interface structures
-        * will point at this one bte_recover structure to get the lock.
-        */
-       spin_lock_init(&mynodepda->bte_recovery_lock);
-       timer_setup(&mynodepda->bte_recovery_timer, bte_recovery_timeout, 0);
-
-       for (i = 0; i < BTES_PER_NODE; i++) {
-               u64 *base_addr;
-
-               /* Which link status register should we use? */
-               base_addr = (u64 *)
-                   REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), BTE_BASE_ADDR(i));
-               mynodepda->bte_if[i].bte_base_addr = base_addr;
-               mynodepda->bte_if[i].bte_source_addr = BTE_SOURCE_ADDR(base_addr);
-               mynodepda->bte_if[i].bte_destination_addr = BTE_DEST_ADDR(base_addr);
-               mynodepda->bte_if[i].bte_control_addr = BTE_CTRL_ADDR(base_addr);
-               mynodepda->bte_if[i].bte_notify_addr = BTE_NOTIF_ADDR(base_addr);
-
-               /*
-                * Initialize the notification and spinlock
-                * so the first transfer can occur.
-                */
-               mynodepda->bte_if[i].most_rcnt_na =
-                   &(mynodepda->bte_if[i].notify);
-               mynodepda->bte_if[i].notify = BTE_WORD_AVAILABLE;
-               spin_lock_init(&mynodepda->bte_if[i].spinlock);
-
-               mynodepda->bte_if[i].bte_cnode = cnode;
-               mynodepda->bte_if[i].bte_error_count = 0;
-               mynodepda->bte_if[i].bte_num = i;
-               mynodepda->bte_if[i].cleanup_active = 0;
-               mynodepda->bte_if[i].bh_error = 0;
-       }
-
-}
diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c
deleted file mode 100644 (file)
index d92786c..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000-2007 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <asm/sn/sn_sal.h>
-#include "ioerror.h"
-#include <asm/sn/addrs.h>
-#include <asm/sn/shubio.h>
-#include <asm/sn/geo.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-#include <asm/sn/bte.h>
-#include <asm/param.h>
-
-/*
- * Bte error handling is done in two parts.  The first captures
- * any crb related errors.  Since there can be multiple crbs per
- * interface and multiple interfaces active, we need to wait until
- * all active crbs are completed.  This is the first job of the
- * second part error handler.  When all bte related CRBs are cleanly
- * completed, it resets the interfaces and gets them ready for new
- * transfers to be queued.
- */
-
-/*
- * Wait until all BTE related CRBs are completed
- * and then reset the interfaces.
- */
-static int shub1_bte_error_handler(struct nodepda_s *err_nodepda)
-{
-       struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
-       nasid_t nasid;
-       int i;
-       int valid_crbs;
-       ii_imem_u_t imem;       /* II IMEM Register */
-       ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
-       ii_ibcr_u_t ibcr;
-       ii_icmr_u_t icmr;
-       ii_ieclr_u_t ieclr;
-
-       BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda,
-                   smp_processor_id()));
-
-       if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) &&
-           (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
-               BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
-                           smp_processor_id()));
-               return 1;
-       }
-
-       /* Determine information about our hub */
-       nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
-
-       /*
-        * A BTE transfer can use multiple CRBs.  We need to make sure
-        * that all the BTE CRBs are complete (or timed out) before
-        * attempting to clean up the error.  Resetting the BTE while
-        * there are still BTE CRBs active will hang the BTE.
-        * We should look at all the CRBs to see if they are allocated
-        * to the BTE and see if they are still active.  When none
-        * are active, we can continue with the cleanup.
-        *
-        * We also want to make sure that the local NI port is up.
-        * When a router resets the NI port can go down, while it
-        * goes through the LLP handshake, but then comes back up.
-        */
-       icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR);
-       if (icmr.ii_icmr_fld_s.i_crb_mark != 0) {
-               /*
-                * There are errors which still need to be cleaned up by
-                * hubiio_crb_error_handler
-                */
-               mod_timer(recovery_timer, jiffies + (HZ * 5));
-               BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
-                           smp_processor_id()));
-               return 1;
-       }
-       if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
-
-               valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld;
-
-               for (i = 0; i < IIO_NUM_CRBS; i++) {
-                       if (!((1 << i) & valid_crbs)) {
-                               /* This crb was not marked as valid, ignore */
-                               continue;
-                       }
-                       icrbd.ii_icrb0_d_regval =
-                           REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
-                       if (icrbd.d_bteop) {
-                               mod_timer(recovery_timer, jiffies + (HZ * 5));
-                               BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
-                                           err_nodepda, smp_processor_id(),
-                                           i));
-                               return 1;
-                       }
-               }
-       }
-
-       BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id()));
-       /* Re-enable both bte interfaces */
-       imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM);
-       imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1;
-       REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval);
-
-       /* Clear BTE0/1 error bits */
-       ieclr.ii_ieclr_regval = 0;
-       if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS)
-               ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1;
-       if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS)
-               ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1;
-       REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval);
-
-       /* Reinitialize both BTE state machines. */
-       ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR);
-       ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
-       REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
-
-       del_timer(recovery_timer);
-       return 0;
-}
-
-/*
- * Wait until all BTE related CRBs are completed
- * and then reset the interfaces.
- */
-static int shub2_bte_error_handler(struct nodepda_s *err_nodepda)
-{
-       struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
-       struct bteinfo_s *bte;
-       nasid_t nasid;
-       u64 status;
-       int i;
-
-       nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
-
-       /*
-        * Verify that all the BTEs are complete
-        */
-       for (i = 0; i < BTES_PER_NODE; i++) {
-               bte = &err_nodepda->bte_if[i];
-               status = BTE_LNSTAT_LOAD(bte);
-               if (status & IBLS_ERROR) {
-                       bte->bh_error = BTE_SHUB2_ERROR(status);
-                       continue;
-               }
-               if (!(status & IBLS_BUSY))
-                       continue;
-               mod_timer(recovery_timer, jiffies + (HZ * 5));
-               BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
-                           smp_processor_id()));
-               return 1;
-       }
-       if (ia64_sn_bte_recovery(nasid))
-               panic("bte_error_handler(): Fatal BTE Error");
-
-       del_timer(recovery_timer);
-       return 0;
-}
-
-/*
- * Wait until all BTE related CRBs are completed
- * and then reset the interfaces.
- */
-void bte_error_handler(struct nodepda_s *err_nodepda)
-{
-       spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
-       int i;
-       unsigned long irq_flags;
-       volatile u64 *notify;
-       bte_result_t bh_error;
-
-       BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda,
-                   smp_processor_id()));
-
-       spin_lock_irqsave(recovery_lock, irq_flags);
-
-       /*
-        * Lock all interfaces on this node to prevent new transfers
-        * from being queued.
-        */
-       for (i = 0; i < BTES_PER_NODE; i++) {
-               if (err_nodepda->bte_if[i].cleanup_active) {
-                       continue;
-               }
-               spin_lock(&err_nodepda->bte_if[i].spinlock);
-               BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda,
-                           smp_processor_id(), i));
-               err_nodepda->bte_if[i].cleanup_active = 1;
-       }
-
-       if (is_shub1()) {
-               if (shub1_bte_error_handler(err_nodepda)) {
-                       spin_unlock_irqrestore(recovery_lock, irq_flags);
-                       return;
-               }
-       } else {
-               if (shub2_bte_error_handler(err_nodepda)) {
-                       spin_unlock_irqrestore(recovery_lock, irq_flags);
-                       return;
-               }
-       }
-
-       for (i = 0; i < BTES_PER_NODE; i++) {
-               bh_error = err_nodepda->bte_if[i].bh_error;
-               if (bh_error != BTE_SUCCESS) {
-                       /* There is an error which needs to be notified */
-                       notify = err_nodepda->bte_if[i].most_rcnt_na;
-                       BTE_PRINTK(("cnode %d bte %d error=0x%lx\n",
-                                   err_nodepda->bte_if[i].bte_cnode,
-                                   err_nodepda->bte_if[i].bte_num,
-                                   IBLS_ERROR | (u64) bh_error));
-                       *notify = IBLS_ERROR | bh_error;
-                       err_nodepda->bte_if[i].bh_error = BTE_SUCCESS;
-               }
-
-               err_nodepda->bte_if[i].cleanup_active = 0;
-               BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda,
-                           smp_processor_id(), i));
-               spin_unlock(&err_nodepda->bte_if[i].spinlock);
-       }
-
-       spin_unlock_irqrestore(recovery_lock, irq_flags);
-}
-
-/*
- * First part error handler.  This is called whenever any error CRB interrupt
- * is generated by the II.
- */
-void
-bte_crb_error_handler(cnodeid_t cnode, int btenum,
-                      int crbnum, ioerror_t * ioe, int bteop)
-{
-       struct bteinfo_s *bte;
-
-
-       bte = &(NODEPDA(cnode)->bte_if[btenum]);
-
-       /*
-        * The caller has already figured out the error type, we save that
-        * in the bte handle structure for the thread exercising the
-        * interface to consume.
-        */
-       bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET;
-       bte->bte_error_count++;
-
-       BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n",
-               bte->bte_cnode, bte->bte_num, ioe->ie_errortype));
-       bte_error_handler(NODEPDA(cnode));
-}
-
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
deleted file mode 100644 (file)
index 97fa56d..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/delay.h>
-#include <asm/sn/sn_sal.h>
-#include "ioerror.h"
-#include <asm/sn/addrs.h>
-#include <asm/sn/shubio.h>
-#include <asm/sn/geo.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-#include <asm/sn/bte.h>
-
-void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
-extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
-                                 int);
-static irqreturn_t hub_eint_handler(int irq, void *arg)
-{
-       struct hubdev_info *hubdev_info;
-       struct ia64_sal_retval ret_stuff;
-       nasid_t nasid;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-       hubdev_info = (struct hubdev_info *)arg;
-       nasid = hubdev_info->hdi_nasid;
-
-       if (is_shub1()) {
-               SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
-                       (u64) nasid, 0, 0, 0, 0, 0, 0);
-
-               if ((int)ret_stuff.v0)
-                       panic("%s: Fatal %s Error", __func__,
-                               ((nasid & 1) ? "TIO" : "HUBII"));
-
-               if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
-                       (void)hubiio_crb_error_handler(hubdev_info);
-       } else
-               if (nasid & 1) {        /* TIO errors */
-                       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
-                               (u64) nasid, 0, 0, 0, 0, 0, 0);
-
-                       if ((int)ret_stuff.v0)
-                               panic("%s: Fatal TIO Error", __func__);
-               } else
-                       bte_error_handler(NODEPDA(nasid_to_cnodeid(nasid)));
-
-       return IRQ_HANDLED;
-}
-
-/*
- * Free the hub CRB "crbnum" which encountered an error.
- * Assumption is, error handling was successfully done,
- * and we now want to return the CRB back to Hub for normal usage.
- *
- * In order to free the CRB, all that's needed is to de-allocate it
- *
- * Assumption:
- *      No other processor is mucking around with the hub control register.
- *      So, upper layer has to single thread this.
- */
-void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
-{
-       ii_icrb0_b_u_t icrbb;
-
-       /*
-        * The hardware does NOT clear the mark bit, so it must get cleared
-        * here to be sure the error is not processed twice.
-        */
-       icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid,
-                                              IIO_ICRB_B(crbnum));
-       icrbb.b_mark = 0;
-       REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum),
-                    icrbb.ii_icrb0_b_regval);
-       /*
-        * Deallocate the register wait till hub indicates it's done.
-        */
-       REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
-       while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
-               cpu_relax();
-
-}
-
-/*
- * hubiio_crb_error_handler
- *
- *     This routine gets invoked when a hub gets an error 
- *     interrupt. So, the routine is running in interrupt context
- *     at error interrupt level.
- * Action:
- *     It's responsible for identifying ALL the CRBs that are marked
- *     with error, and process them. 
- *     
- *     If you find the CRB that's marked with error, map this to the
- *     reason it caused error, and invoke appropriate error handler.
- *
- *     XXX Be aware of the information in the context register.
- *
- * NOTE:
- *     Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt
- *     handler can be run on any node. (not necessarily the node 
- *     corresponding to the hub that encountered error).
- */
-
-void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
-{
-       nasid_t nasid;
-       ii_icrb0_a_u_t icrba;   /* II CRB Register A */
-       ii_icrb0_b_u_t icrbb;   /* II CRB Register B */
-       ii_icrb0_c_u_t icrbc;   /* II CRB Register C */
-       ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
-       ii_icrb0_e_u_t icrbe;   /* II CRB Register D */
-       int i;
-       int num_errors = 0;     /* Num of errors handled */
-       ioerror_t ioerror;
-
-       nasid = hubdev_info->hdi_nasid;
-
-       /*
-        * XXX - Add locking for any recovery actions
-        */
-       /*
-        * Scan through all CRBs in the Hub, and handle the errors
-        * in any of the CRBs marked.
-        */
-       for (i = 0; i < IIO_NUM_CRBS; i++) {
-               /* Check this crb entry to see if it is in error. */
-               icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
-
-               if (icrbb.b_mark == 0) {
-                       continue;
-               }
-
-               icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
-
-               IOERROR_INIT(&ioerror);
-
-               /* read other CRB error registers. */
-               icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
-               icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
-               icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
-
-               IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode);
-
-               /* Check if this error is due to BTE operation,
-                * and handle it separately.
-                */
-               if (icrbd.d_bteop ||
-                   ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 ||
-                     icrbb.b_initiator == IIO_ICRB_INIT_BTE1) &&
-                    (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE ||
-                     icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) {
-
-                       int bte_num;
-
-                       if (icrbd.d_bteop)
-                               bte_num = icrbc.c_btenum;
-                       else    /* b_initiator bit 2 gives BTE number */
-                               bte_num = (icrbb.b_initiator & 0x4) >> 2;
-
-                       hubiio_crb_free(hubdev_info, i);
-
-                       bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num,
-                                             i, &ioerror, icrbd.d_bteop);
-                       num_errors++;
-                       continue;
-               }
-       }
-}
-
-/*
- * Function    : hub_error_init
- * Purpose     : initialize the error handling requirements for a given hub.
- * Parameters  : cnode, the compact nodeid.
- * Assumptions : Called only once per hub, either by a local cpu. Or by a
- *                     remote cpu, when this hub is headless.(cpuless)
- * Returns     : None
- */
-void hub_error_init(struct hubdev_info *hubdev_info)
-{
-
-       if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED,
-                       "SN_hub_error", hubdev_info)) {
-               printk(KERN_ERR "hub_error_init: Failed to request_irq for 0x%p\n",
-                   hubdev_info);
-               return;
-       }
-       irq_set_handler(SGI_II_ERROR, handle_level_irq);
-       sn_set_err_irq_affinity(SGI_II_ERROR);
-}
-
-
-/*
- * Function    : ice_error_init
- * Purpose     : initialize the error handling requirements for a given tio.
- * Parameters  : cnode, the compact nodeid.
- * Assumptions : Called only once per tio.
- * Returns     : None
- */
-void ice_error_init(struct hubdev_info *hubdev_info)
-{
-
-        if (request_irq
-            (SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error",
-             (void *)hubdev_info)) {
-                printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",
-                       hubdev_info);
-               return;
-       }
-       irq_set_handler(SGI_TIO_ERROR, handle_level_irq);
-       sn_set_err_irq_affinity(SGI_TIO_ERROR);
-}
-
diff --git a/arch/ia64/sn/kernel/idle.c b/arch/ia64/sn/kernel/idle.c
deleted file mode 100644 (file)
index 49d178f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2001-2004 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#include <asm/sn/leds.h>
-
-void snidle(int state)
-{
-       if (state) {
-               if (pda->idle_flag == 0) {
-                       /* 
-                        * Turn the activity LED off.
-                        */
-                       set_led_bits(0, LED_CPU_ACTIVITY);
-               }
-
-               pda->idle_flag = 1;
-       } else {
-               /* 
-                * Turn the activity LED on.
-                */
-               set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY);
-
-               pda->idle_flag = 0;
-       }
-}
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c
deleted file mode 100644 (file)
index c31fe63..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <asm/sn/types.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/sn_sal.h>
-#include "xtalk/hubdev.h"
-#include <linux/acpi.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-
-/*
- * The code in this file will only be executed when running with
- * a PROM that has ACPI IO support. (i.e., SN_ACPI_BASE_SUPPORT() == 1)
- */
-
-
-/*
- * This value must match the UUID the PROM uses
- * (io/acpi/defblk.c) when building a vendor descriptor.
- */
-struct acpi_vendor_uuid sn_uuid = {
-       .subtype = 0,
-       .data   = { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11,
-                   0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
-};
-
-struct sn_pcidev_match {
-       u8 bus;
-       unsigned int devfn;
-       acpi_handle handle;
-};
-
-/*
- * Perform the early IO init in PROM.
- */
-static long
-sal_ioif_init(u64 *result)
-{
-       struct ia64_sal_retval isrv = {0,0,0,0};
-
-       SAL_CALL_NOLOCK(isrv,
-                       SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0);
-       *result = isrv.v0;
-       return isrv.status;
-}
-
-/*
- * sn_acpi_hubdev_init() - This function is called by acpi_ns_get_device_callback()
- *                        for all SGIHUB and SGITIO acpi devices defined in the
- *                        DSDT. It obtains the hubdev_info pointer from the
- *                        ACPI vendor resource, which the PROM setup, and sets up the
- *                        hubdev_info in the pda.
- */
-
-static acpi_status __init
-sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       u64 addr;
-       struct hubdev_info *hubdev;
-       struct hubdev_info *hubdev_ptr;
-       int i;
-       u64 nasid;
-       struct acpi_resource *resource;
-       acpi_status status;
-       struct acpi_resource_vendor_typed *vendor;
-       extern void sn_common_hubdev_init(struct hubdev_info *);
-
-       status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
-                                         &sn_uuid, &buffer);
-       if (ACPI_FAILURE(status)) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR
-                      "sn_acpi_hubdev_init: acpi_get_vendor_resource() "
-                      "(0x%x) failed for: %s\n", status,
-                       (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               return AE_OK;           /* Continue walking namespace */
-       }
-
-       resource = buffer.pointer;
-       vendor = &resource->data.vendor_typed;
-       if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
-           sizeof(struct hubdev_info *)) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR
-                      "sn_acpi_hubdev_init: Invalid vendor data length: "
-                      "%d for: %s\n",
-                       vendor->byte_length, (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               goto exit;
-       }
-
-       memcpy(&addr, vendor->byte_data, sizeof(struct hubdev_info *));
-       hubdev_ptr = __va((struct hubdev_info *) addr);
-
-       nasid = hubdev_ptr->hdi_nasid;
-       i = nasid_to_cnodeid(nasid);
-       hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
-       *hubdev = *hubdev_ptr;
-       sn_common_hubdev_init(hubdev);
-
-exit:
-       kfree(buffer.pointer);
-       return AE_OK;           /* Continue walking namespace */
-}
-
-/*
- * sn_get_bussoft_ptr() - The pcibus_bussoft pointer is found in
- *                       the ACPI Vendor resource for this bus.
- */
-static struct pcibus_bussoft *
-sn_get_bussoft_ptr(struct pci_bus *bus)
-{
-       u64 addr;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       acpi_handle handle;
-       struct pcibus_bussoft *prom_bussoft_ptr;
-       struct acpi_resource *resource;
-       acpi_status status;
-       struct acpi_resource_vendor_typed *vendor;
-
-
-       handle = acpi_device_handle(PCI_CONTROLLER(bus)->companion);
-       status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
-                                         &sn_uuid, &buffer);
-       if (ACPI_FAILURE(status)) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR "%s: "
-                      "acpi_get_vendor_resource() failed (0x%x) for: %s\n",
-                      __func__, status, (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               return NULL;
-       }
-       resource = buffer.pointer;
-       vendor = &resource->data.vendor_typed;
-
-       if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
-            sizeof(struct pcibus_bussoft *)) {
-               printk(KERN_ERR
-                      "%s: Invalid vendor data length %d\n",
-                       __func__, vendor->byte_length);
-               kfree(buffer.pointer);
-               return NULL;
-       }
-       memcpy(&addr, vendor->byte_data, sizeof(struct pcibus_bussoft *));
-       prom_bussoft_ptr = __va((struct pcibus_bussoft *) addr);
-       kfree(buffer.pointer);
-
-       return prom_bussoft_ptr;
-}
-
-/*
- * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info
- *                         pointers from the vendor resource using the
- *                         provided acpi handle, and copy the structures
- *                         into the argument buffers.
- */
-static int
-sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info,
-                   struct sn_irq_info **sn_irq_info)
-{
-       u64 addr;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct sn_irq_info *irq_info, *irq_info_prom;
-       struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr;
-       struct acpi_resource *resource;
-       int ret = 0;
-       acpi_status status;
-       struct acpi_resource_vendor_typed *vendor;
-
-       /*
-        * The pointer to this device's pcidev_info structure in
-        * the PROM, is in the vendor resource.
-        */
-       status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
-                                         &sn_uuid, &buffer);
-       if (ACPI_FAILURE(status)) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR
-                      "%s: acpi_get_vendor_resource() failed (0x%x) for: %s\n",
-                       __func__, status, (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               return 1;
-       }
-
-       resource = buffer.pointer;
-       vendor = &resource->data.vendor_typed;
-       if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
-           sizeof(struct pci_devdev_info *)) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR
-                      "%s: Invalid vendor data length: %d for: %s\n",
-                        __func__, vendor->byte_length,
-                       (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               ret = 1;
-               goto exit;
-       }
-
-       pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-       if (!pcidev_ptr)
-               panic("%s: Unable to alloc memory for pcidev_info", __func__);
-
-       memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *));
-       pcidev_prom_ptr = __va(addr);
-       memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info));
-
-       /* Get the IRQ info */
-       irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (!irq_info)
-                panic("%s: Unable to alloc memory for sn_irq_info", __func__);
-
-       if (pcidev_ptr->pdi_sn_irq_info) {
-               irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info);
-               memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info));
-       }
-
-       *pcidev_info = pcidev_ptr;
-       *sn_irq_info = irq_info;
-
-exit:
-       kfree(buffer.pointer);
-       return ret;
-}
-
-static unsigned int
-get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
-{
-       unsigned long long adr;
-       acpi_handle child;
-       unsigned int devfn;
-       int function;
-       acpi_handle parent;
-       int slot;
-       acpi_status status;
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       acpi_get_name(device_handle, ACPI_FULL_PATHNAME, &name_buffer);
-
-       /*
-        * Do an upward search to find the root bus device, and
-        * obtain the host devfn from the previous child device.
-        */
-       child = device_handle;
-       while (child) {
-               status = acpi_get_parent(child, &parent);
-               if (ACPI_FAILURE(status)) {
-                       printk(KERN_ERR "%s: acpi_get_parent() failed "
-                              "(0x%x) for: %s\n", __func__, status,
-                               (char *)name_buffer.pointer);
-                       panic("%s: Unable to find host devfn\n", __func__);
-               }
-               if (parent == rootbus_handle)
-                       break;
-               child = parent;
-       }
-       if (!child) {
-               printk(KERN_ERR "%s: Unable to find root bus for: %s\n",
-                      __func__, (char *)name_buffer.pointer);
-               BUG();
-       }
-
-       status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: %s\n",
-                      __func__, status, (char *)name_buffer.pointer);
-               panic("%s: Unable to find host devfn\n", __func__);
-       }
-
-       kfree(name_buffer.pointer);
-
-       slot = (adr >> 16) & 0xffff;
-       function = adr & 0xffff;
-       devfn = PCI_DEVFN(slot, function);
-       return devfn;
-}
-
-/*
- * find_matching_device - Callback routine to find the ACPI device
- *                       that matches up with our pci_dev device.
- *                       Matching is done on bus number and devfn.
- *                       To find the bus number for a particular
- *                       ACPI device, we must look at the _BBN method
- *                       of its parent.
- */
-static acpi_status
-find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       unsigned long long bbn = -1;
-       unsigned long long adr;
-       acpi_handle parent = NULL;
-       acpi_status status;
-       unsigned int devfn;
-       int function;
-       int slot;
-       struct sn_pcidev_match *info = context;
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
-                                       &adr);
-        if (ACPI_SUCCESS(status)) {
-               status = acpi_get_parent(handle, &parent);
-               if (ACPI_FAILURE(status)) {
-                       acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-                       printk(KERN_ERR
-                              "%s: acpi_get_parent() failed (0x%x) for: %s\n",
-                               __func__, status, (char *)name_buffer.pointer);
-                       kfree(name_buffer.pointer);
-                       return AE_OK;
-               }
-               status = acpi_evaluate_integer(parent, METHOD_NAME__BBN,
-                                              NULL, &bbn);
-               if (ACPI_FAILURE(status)) {
-                       acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
-                       printk(KERN_ERR
-                         "%s: Failed to find _BBN in parent of: %s\n",
-                                       __func__, (char *)name_buffer.pointer);
-                       kfree(name_buffer.pointer);
-                       return AE_OK;
-               }
-
-                slot = (adr >> 16) & 0xffff;
-                function = adr & 0xffff;
-                devfn = PCI_DEVFN(slot, function);
-                if ((info->devfn == devfn) && (info->bus == bbn)) {
-                       /* We have a match! */
-                       info->handle = handle;
-                       return 1;
-               }
-       }
-       return AE_OK;
-}
-
-/*
- * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi
- *                          device matching the specified pci_dev,
- *                          and return the pcidev info and irq info.
- */
-int
-sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
-                       struct sn_irq_info **sn_irq_info)
-{
-       unsigned int host_devfn;
-       struct sn_pcidev_match pcidev_match;
-       acpi_handle rootbus_handle;
-       unsigned long long segment;
-       acpi_status status;
-       struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       rootbus_handle = acpi_device_handle(PCI_CONTROLLER(dev)->companion);
-        status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
-                                       &segment);
-        if (ACPI_SUCCESS(status)) {
-               if (segment != pci_domain_nr(dev)) {
-                       acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME,
-                               &name_buffer);
-                       printk(KERN_ERR
-                              "%s: Segment number mismatch, 0x%llx vs 0x%x for: %s\n",
-                              __func__, segment, pci_domain_nr(dev),
-                              (char *)name_buffer.pointer);
-                       kfree(name_buffer.pointer);
-                       return 1;
-               }
-       } else {
-               acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, &name_buffer);
-               printk(KERN_ERR "%s: Unable to get __SEG from: %s\n",
-                      __func__, (char *)name_buffer.pointer);
-               kfree(name_buffer.pointer);
-               return 1;
-       }
-
-       /*
-        * We want to search all devices in this segment/domain
-        * of the ACPI namespace for the matching ACPI device,
-        * which holds the pcidev_info pointer in its vendor resource.
-        */
-       pcidev_match.bus = dev->bus->number;
-       pcidev_match.devfn = dev->devfn;
-       pcidev_match.handle = NULL;
-
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
-                           find_matching_device, NULL, &pcidev_match, NULL);
-
-       if (!pcidev_match.handle) {
-               printk(KERN_ERR
-                      "%s: Could not find matching ACPI device for %s.\n",
-                      __func__, pci_name(dev));
-               return 1;
-       }
-
-       if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info))
-               return 1;
-
-       /* Build up the pcidev_info.pdi_slot_host_handle */
-       host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
-       (*pcidev_info)->pdi_slot_host_handle =
-                       ((unsigned long) pci_domain_nr(dev) << 40) |
-                                       /* bus == 0 */
-                                       host_devfn;
-       return 0;
-}
-
-/*
- * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info.
- *                     Perform any SN specific slot fixup.
- *                     At present there does not appear to be
- *                     any generic way to handle a ROM image
- *                     that has been shadowed by the PROM, so
- *                     we pass a pointer to it within the
- *                     pcidev_info structure.
- */
-
-void
-sn_acpi_slot_fixup(struct pci_dev *dev)
-{
-       struct pcidev_info *pcidev_info = NULL;
-       struct sn_irq_info *sn_irq_info = NULL;
-       struct resource *res;
-       size_t size;
-
-       if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
-               panic("%s:  Failure obtaining pcidev_info for %s\n",
-                     __func__, pci_name(dev));
-       }
-
-       if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
-               /*
-                * A valid ROM image exists and has been shadowed by the
-                * PROM. Setup the pci_dev ROM resource with the address
-                * of the shadowed copy, and the actual length of the ROM image.
-                */
-               size = pci_resource_len(dev, PCI_ROM_RESOURCE);
-
-               res = &dev->resource[PCI_ROM_RESOURCE];
-
-               pci_disable_rom(dev);
-               if (res->parent)
-                       release_resource(res);
-
-               res->start = pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE];
-               res->end = res->start + size - 1;
-               res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW |
-                            IORESOURCE_PCI_FIXED;
-       }
-       sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
-}
-EXPORT_SYMBOL(sn_acpi_slot_fixup);
-
-
-/*
- * sn_acpi_bus_fixup -  Perform SN specific setup of software structs
- *                     (pcibus_bussoft, pcidev_info) and hardware
- *                     registers, for the specified bus and devices under it.
- */
-void
-sn_acpi_bus_fixup(struct pci_bus *bus)
-{
-       struct pci_dev *pci_dev = NULL;
-       struct pcibus_bussoft *prom_bussoft_ptr;
-
-       if (!bus->parent) {     /* If root bus */
-               prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
-               if (prom_bussoft_ptr == NULL) {
-                       printk(KERN_ERR
-                              "%s: 0x%04x:0x%02x Unable to "
-                              "obtain prom_bussoft_ptr\n",
-                              __func__, pci_domain_nr(bus), bus->number);
-                       return;
-               }
-               sn_common_bus_fixup(bus, prom_bussoft_ptr);
-       }
-       list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-               sn_acpi_slot_fixup(pci_dev);
-       }
-}
-
-/*
- * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
- *                  nodes and root buses in the DSDT. As a result, bus scanning
- *                  will be initiated by the Linux ACPI code.
- */
-
-void __init
-sn_io_acpi_init(void)
-{
-       u64 result;
-       long status;
-
-       /* SN Altix does not follow the IOSAPIC IRQ routing model */
-       acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
-
-       /* Setup hubdev_info for all SGIHUB/SGITIO devices */
-       acpi_get_devices("SGIHUB", sn_acpi_hubdev_init, NULL, NULL);
-       acpi_get_devices("SGITIO", sn_acpi_hubdev_init, NULL, NULL);
-
-       status = sal_ioif_init(&result);
-       if (status || result)
-               panic("sal_ioif_init failed: [%lx] %s\n",
-                     status, ia64_sal_strerror(status));
-}
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
deleted file mode 100644 (file)
index d468473..0000000
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/memblock.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <asm/sn/types.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/sn_feature_sets.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/io.h>
-#include <asm/sn/l1.h>
-#include <asm/sn/module.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/tioca_provider.h>
-#include <asm/sn/tioce_provider.h>
-#include "xtalk/hubdev.h"
-#include "xtalk/xwidgetdev.h"
-#include <linux/acpi.h>
-#include <asm/sn/sn2/sn_hwperf.h>
-#include <asm/sn/acpi.h>
-
-extern void sn_init_cpei_timer(void);
-extern void register_sn_procfs(void);
-extern void sn_io_acpi_init(void);
-extern void sn_io_init(void);
-
-
-static struct list_head sn_sysdata_list;
-
-/* sysdata list struct */
-struct sysdata_el {
-       struct list_head entry;
-       void *sysdata;
-};
-
-int sn_ioif_inited;            /* SN I/O infrastructure initialized? */
-
-int sn_acpi_rev;               /* SN ACPI revision */
-EXPORT_SYMBOL_GPL(sn_acpi_rev);
-
-struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];      /* indexed by asic type */
-
-/*
- * Hooks and struct for unsupported pci providers
- */
-
-static dma_addr_t
-sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
-{
-       return 0;
-}
-
-static void
-sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction)
-{
-       return;
-}
-
-static void *
-sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller)
-{
-       return NULL;
-}
-
-static struct sn_pcibus_provider sn_pci_default_provider = {
-       .dma_map = sn_default_pci_map,
-       .dma_map_consistent = sn_default_pci_map,
-       .dma_unmap = sn_default_pci_unmap,
-       .bus_fixup = sn_default_pci_bus_fixup,
-};
-
-/*
- * Retrieve the DMA Flush List given nasid, widget, and device.
- * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
- */
-static inline u64
-sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
-                            u64 address)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
-                       (u64) nasid, (u64) widget_num,
-                       (u64) device_num, (u64) address, 0, 0, 0);
-       return ret_stuff.status;
-}
-
-/*
- * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
- *                       device.
- */
-inline struct pcidev_info *
-sn_pcidev_info_get(struct pci_dev *dev)
-{
-       struct pcidev_info *pcidev;
-
-       list_for_each_entry(pcidev,
-                           &(SN_PLATFORM_DATA(dev)->pcidev_info), pdi_list) {
-               if (pcidev->pdi_linux_pcidev == dev)
-                       return pcidev;
-       }
-       return NULL;
-}
-
-/* Older PROM flush WAR
- *
- * 01/16/06 -- This war will be in place until a new official PROM is released.
- * Additionally note that the struct sn_flush_device_war also has to be
- * removed from arch/ia64/sn/include/xtalk/hubdev.h
- */
-
-static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
-                              struct sn_flush_device_common *common)
-{
-       struct sn_flush_device_war *war_list;
-       struct sn_flush_device_war *dev_entry;
-       struct ia64_sal_retval isrv = {0,0,0,0};
-
-       printk_once(KERN_WARNING
-               "PROM version < 4.50 -- implementing old PROM flush WAR\n");
-
-       war_list = kcalloc(DEV_PER_WIDGET, sizeof(*war_list), GFP_KERNEL);
-       BUG_ON(!war_list);
-
-       SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
-                       nasid, widget, __pa(war_list), 0, 0, 0 ,0);
-       if (isrv.status)
-               panic("sn_device_fixup_war failed: %s\n",
-                     ia64_sal_strerror(isrv.status));
-
-       dev_entry = war_list + device;
-       memcpy(common,dev_entry, sizeof(*common));
-       kfree(war_list);
-
-       return isrv.status;
-}
-
-/*
- * sn_common_hubdev_init() - This routine is called to initialize the HUB data
- *                          structure for each node in the system.
- */
-void __init
-sn_common_hubdev_init(struct hubdev_info *hubdev)
-{
-
-       struct sn_flush_device_kernel *sn_flush_device_kernel;
-       struct sn_flush_device_kernel *dev_entry;
-       s64 status;
-       int widget, device, size;
-
-       /* Attach the error interrupt handlers */
-       if (hubdev->hdi_nasid & 1)      /* If TIO */
-               ice_error_init(hubdev);
-       else
-               hub_error_init(hubdev);
-
-       for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
-               hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;
-
-       if (!hubdev->hdi_flush_nasid_list.widget_p)
-               return;
-
-       size = (HUB_WIDGET_ID_MAX + 1) *
-               sizeof(struct sn_flush_device_kernel *);
-       hubdev->hdi_flush_nasid_list.widget_p =
-               kzalloc(size, GFP_KERNEL);
-       BUG_ON(!hubdev->hdi_flush_nasid_list.widget_p);
-
-       for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
-               size = DEV_PER_WIDGET *
-                       sizeof(struct sn_flush_device_kernel);
-               sn_flush_device_kernel = kzalloc(size, GFP_KERNEL);
-               BUG_ON(!sn_flush_device_kernel);
-
-               dev_entry = sn_flush_device_kernel;
-               for (device = 0; device < DEV_PER_WIDGET;
-                    device++, dev_entry++) {
-                       size = sizeof(struct sn_flush_device_common);
-                       dev_entry->common = kzalloc(size, GFP_KERNEL);
-                       BUG_ON(!dev_entry->common);
-                       if (sn_prom_feature_available(PRF_DEVICE_FLUSH_LIST))
-                               status = sal_get_device_dmaflush_list(
-                                            hubdev->hdi_nasid, widget, device,
-                                            (u64)(dev_entry->common));
-                       else
-                               status = sn_device_fixup_war(hubdev->hdi_nasid,
-                                                            widget, device,
-                                                            dev_entry->common);
-                       if (status != SALRET_OK)
-                               panic("SAL call failed: %s\n",
-                                     ia64_sal_strerror(status));
-
-                       spin_lock_init(&dev_entry->sfdl_flush_lock);
-               }
-
-               if (sn_flush_device_kernel)
-                       hubdev->hdi_flush_nasid_list.widget_p[widget] =
-                                                        sn_flush_device_kernel;
-       }
-}
-
-void sn_pci_unfixup_slot(struct pci_dev *dev)
-{
-       struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
-
-       sn_irq_unfixup(dev);
-       pci_dev_put(host_pci_dev);
-       pci_dev_put(dev);
-}
-
-/*
- * sn_pci_fixup_slot()
- */
-void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info,
-                      struct sn_irq_info *sn_irq_info)
-{
-       int segment = pci_domain_nr(dev->bus);
-       struct pcibus_bussoft *bs;
-       struct pci_dev *host_pci_dev;
-       unsigned int bus_no, devfn;
-
-       pci_dev_get(dev); /* for the sysdata pointer */
-
-       /* Add pcidev_info to list in pci_controller.platform_data */
-       list_add_tail(&pcidev_info->pdi_list,
-                     &(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
-       /*
-        * Using the PROMs values for the PCI host bus, get the Linux
-        * PCI host_pci_dev struct and set up host bus linkages
-        */
-
-       bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
-       devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
-       host_pci_dev = pci_get_domain_bus_and_slot(segment, bus_no, devfn);
-
-       pcidev_info->host_pci_dev = host_pci_dev;
-       pcidev_info->pdi_linux_pcidev = dev;
-       pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
-       bs = SN_PCIBUS_BUSSOFT(dev->bus);
-       pcidev_info->pdi_pcibus_info = bs;
-
-       if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
-               SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
-       } else {
-               SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider;
-       }
-
-       /* Only set up IRQ stuff if this device has a host bus context */
-       if (bs && sn_irq_info->irq_irq) {
-               pcidev_info->pdi_sn_irq_info = sn_irq_info;
-               dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
-               sn_irq_fixup(dev, sn_irq_info);
-       } else {
-               pcidev_info->pdi_sn_irq_info = NULL;
-               kfree(sn_irq_info);
-       }
-}
-
-/*
- * sn_common_bus_fixup - Perform platform specific bus fixup.
- *                      Execute the ASIC specific fixup routine
- *                      for this bus.
- */
-void
-sn_common_bus_fixup(struct pci_bus *bus,
-                   struct pcibus_bussoft *prom_bussoft_ptr)
-{
-       int cnode;
-       struct pci_controller *controller;
-       struct hubdev_info *hubdev_info;
-       int nasid;
-       void *provider_soft;
-       struct sn_pcibus_provider *provider;
-       struct sn_platform_data *sn_platform_data;
-
-       controller = PCI_CONTROLLER(bus);
-       /*
-        * Per-provider fixup.  Copies the bus soft structure from prom
-        * to local area and links SN_PCIBUS_BUSSOFT().
-        */
-
-       if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) {
-               printk(KERN_WARNING "sn_common_bus_fixup: Unsupported asic type, %d",
-                      prom_bussoft_ptr->bs_asic_type);
-               return;
-       }
-
-       if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
-               return; /* no further fixup necessary */
-
-       provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
-       if (provider == NULL)
-               panic("sn_common_bus_fixup: No provider registered for this asic type, %d",
-                     prom_bussoft_ptr->bs_asic_type);
-
-       if (provider->bus_fixup)
-               provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr,
-                                controller);
-       else
-               provider_soft = NULL;
-
-       /*
-        * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
-        * after this point.
-        */
-       controller->platform_data = kzalloc(sizeof(struct sn_platform_data),
-                                           GFP_KERNEL);
-       BUG_ON(controller->platform_data == NULL);
-       sn_platform_data =
-                       (struct sn_platform_data *) controller->platform_data;
-       sn_platform_data->provider_soft = provider_soft;
-       INIT_LIST_HEAD(&((struct sn_platform_data *)
-                        controller->platform_data)->pcidev_info);
-       nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
-       cnode = nasid_to_cnodeid(nasid);
-       hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
-       SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
-           &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
-
-       /*
-        * If the node information we obtained during the fixup phase is
-        * invalid then set controller->node to -1 (undetermined)
-        */
-       if (controller->node >= num_online_nodes()) {
-               struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
-
-               printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u "
-                      "L_IO=%llx L_MEM=%llx BASE=%llx\n",
-                      b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
-                      b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
-               printk(KERN_WARNING "on node %d but only %d nodes online."
-                      "Association set to undetermined.\n",
-                      controller->node, num_online_nodes());
-               controller->node = -1;
-       }
-}
-
-void sn_bus_store_sysdata(struct pci_dev *dev)
-{
-       struct sysdata_el *element;
-
-       element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
-       if (!element) {
-               dev_dbg(&dev->dev, "%s: out of memory!\n", __func__);
-               return;
-       }
-       element->sysdata = SN_PCIDEV_INFO(dev);
-       list_add(&element->entry, &sn_sysdata_list);
-}
-
-void sn_bus_free_sysdata(void)
-{
-       struct sysdata_el *element;
-       struct list_head *list, *safe;
-
-       list_for_each_safe(list, safe, &sn_sysdata_list) {
-               element = list_entry(list, struct sysdata_el, entry);
-               list_del(&element->entry);
-               list_del(&(((struct pcidev_info *)
-                            (element->sysdata))->pdi_list));
-               kfree(element->sysdata);
-               kfree(element);
-       }
-       return;
-}
-
-/*
- * hubdev_init_node() - Creates the HUB data structure and link them to it's
- *                     own NODE specific data area.
- */
-void __init hubdev_init_node(nodepda_t * npda, cnodeid_t node)
-{
-       struct hubdev_info *hubdev_info;
-       int size;
-
-       size = sizeof(struct hubdev_info);
-
-       if (node >= num_online_nodes()) /* Headless/memless IO nodes */
-               node = 0;
-
-       hubdev_info = (struct hubdev_info *)memblock_alloc_node(size,
-                                                               SMP_CACHE_BYTES,
-                                                               node);
-       if (!hubdev_info)
-               panic("%s: Failed to allocate %d bytes align=0x%x nid=%d\n",
-                     __func__, size, SMP_CACHE_BYTES, node);
-
-       npda->pdinfo = (void *)hubdev_info;
-}
-
-geoid_t
-cnodeid_get_geoid(cnodeid_t cnode)
-{
-       struct hubdev_info *hubdev;
-
-       hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
-       return hubdev->hdi_geoid;
-}
-
-void sn_generate_path(struct pci_bus *pci_bus, char *address)
-{
-       nasid_t nasid;
-       cnodeid_t cnode;
-       geoid_t geoid;
-       moduleid_t moduleid;
-       u16 bricktype;
-
-       nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base);
-       cnode = nasid_to_cnodeid(nasid);
-       geoid = cnodeid_get_geoid(cnode);
-       moduleid = geo_module(geoid);
-
-       sprintf(address, "module_%c%c%c%c%.2d",
-               '0'+RACK_GET_CLASS(MODULE_GET_RACK(moduleid)),
-               '0'+RACK_GET_GROUP(MODULE_GET_RACK(moduleid)),
-               '0'+RACK_GET_NUM(MODULE_GET_RACK(moduleid)),
-               MODULE_GET_BTCHAR(moduleid), MODULE_GET_BPOS(moduleid));
-
-       /* Tollhouse requires slot id to be displayed */
-       bricktype = MODULE_GET_BTYPE(moduleid);
-       if ((bricktype == L1_BRICKTYPE_191010) ||
-           (bricktype == L1_BRICKTYPE_1932))
-                       sprintf(address + strlen(address), "^%d",
-                                               geo_slot(geoid));
-}
-
-void sn_pci_fixup_bus(struct pci_bus *bus)
-{
-
-       if (SN_ACPI_BASE_SUPPORT())
-               sn_acpi_bus_fixup(bus);
-       else
-               sn_bus_fixup(bus);
-}
-
-/*
- * sn_io_early_init - Perform early IO (and some non-IO) initialization.
- *                   In particular, setup the sn_pci_provider[] array.
- *                   This needs to be done prior to any bus scanning
- *                   (acpi_scan_init()) in the ACPI case, as the SN
- *                   bus fixup code will reference the array.
- */
-static int __init
-sn_io_early_init(void)
-{
-       int i;
-
-       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
-               return 0;
-
-       /* we set the acpi revision to that of the DSDT table OEM rev. */
-       {
-               struct acpi_table_header *header = NULL;
-
-               acpi_get_table(ACPI_SIG_DSDT, 1, &header);
-               BUG_ON(header == NULL);
-               sn_acpi_rev = header->oem_revision;
-       }
-
-       /*
-        * prime sn_pci_provider[].  Individual provider init routines will
-        * override their respective default entries.
-        */
-
-       for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++)
-               sn_pci_provider[i] = &sn_pci_default_provider;
-
-       pcibr_init_provider();
-       tioca_init_provider();
-       tioce_init_provider();
-
-       sn_irq_lh_init();
-       INIT_LIST_HEAD(&sn_sysdata_list);
-       sn_init_cpei_timer();
-
-#ifdef CONFIG_PROC_FS
-       register_sn_procfs();
-#endif
-
-       {
-               struct acpi_table_header *header;
-               (void)acpi_get_table(ACPI_SIG_DSDT, 1, &header);
-               printk(KERN_INFO "ACPI  DSDT OEM Rev 0x%x\n",
-                       header->oem_revision);
-       }
-       if (SN_ACPI_BASE_SUPPORT())
-               sn_io_acpi_init();
-       else
-               sn_io_init();
-       return 0;
-}
-
-arch_initcall(sn_io_early_init);
-
-/*
- * sn_io_late_init() - Perform any final platform specific IO initialization.
- */
-
-int __init
-sn_io_late_init(void)
-{
-       struct pci_bus *bus;
-       struct pcibus_bussoft *bussoft;
-       cnodeid_t cnode;
-       nasid_t nasid;
-       cnodeid_t near_cnode;
-
-       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
-               return 0;
-
-       /*
-        * Setup closest node in pci_controller->node for
-        * PIC, TIOCP, TIOCE (TIOCA does it during bus fixup using
-        * info from the PROM).
-        */
-       bus = NULL;
-       while ((bus = pci_find_next_bus(bus)) != NULL) {
-               bussoft = SN_PCIBUS_BUSSOFT(bus);
-               nasid = NASID_GET(bussoft->bs_base);
-               cnode = nasid_to_cnodeid(nasid);
-               if ((bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) ||
-                   (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCE) ||
-                   (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_PIC)) {
-                       /* PCI Bridge: find nearest node with CPUs */
-                       int e = sn_hwperf_get_nearest_node(cnode, NULL,
-                                                          &near_cnode);
-                       if (e < 0) {
-                               near_cnode = (cnodeid_t)-1; /* use any node */
-                               printk(KERN_WARNING "sn_io_late_init: failed "
-                                      "to find near node with CPUs for "
-                                      "node %d, err=%d\n", cnode, e);
-                       }
-                       PCI_CONTROLLER(bus)->node = near_cnode;
-               }
-       }
-
-       sn_ioif_inited = 1;     /* SN I/O infrastructure now initialized */
-
-       return 0;
-}
-
-fs_initcall(sn_io_late_init);
-
-EXPORT_SYMBOL(sn_pci_unfixup_slot);
-EXPORT_SYMBOL(sn_bus_store_sysdata);
-EXPORT_SYMBOL(sn_bus_free_sysdata);
-EXPORT_SYMBOL(sn_generate_path);
-
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
deleted file mode 100644 (file)
index d63809a..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <asm/sn/types.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/module.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/sn_sal.h>
-#include "xtalk/hubdev.h"
-
-/*
- * The code in this file will only be executed when running with
- * a PROM that does _not_ have base ACPI IO support.
- * (i.e., SN_ACPI_BASE_SUPPORT() == 0)
- */
-
-static int max_segment_number;          /* Default highest segment number */
-static int max_pcibus_number = 255;    /* Default highest pci bus number */
-
-
-/*
- * Retrieve the hub device info structure for the given nasid.
- */
-static inline u64 sal_get_hubdev_info(u64 handle, u64 address)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_HUBDEV_INFO,
-                       (u64) handle, (u64) address, 0, 0, 0, 0, 0);
-       return ret_stuff.v0;
-}
-
-/*
- * Retrieve the pci bus information given the bus number.
- */
-static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_PCIBUS_INFO,
-                       (u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0);
-       return ret_stuff.v0;
-}
-
-/*
- * Retrieve the pci device information given the bus and device|function number.
- */
-static inline u64
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
-                   u64 sn_irq_info)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
-                       (u64) segment, (u64) bus_number, (u64) devfn,
-                       (u64) pci_dev,
-                       sn_irq_info, 0, 0);
-       return ret_stuff.v0;
-}
-
-
-/*
- * sn_fixup_ionodes() - This routine initializes the HUB data structure for
- *                     each node in the system. This function is only
- *                     executed when running with a non-ACPI capable PROM.
- */
-static void __init sn_fixup_ionodes(void)
-{
-
-       struct hubdev_info *hubdev;
-       u64 status;
-       u64 nasid;
-       int i;
-       extern void sn_common_hubdev_init(struct hubdev_info *);
-
-       /*
-        * Get SGI Specific HUB chipset information.
-        * Inform Prom that this kernel can support domain bus numbering.
-        */
-       for (i = 0; i < num_cnodes; i++) {
-               hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
-               nasid = cnodeid_to_nasid(i);
-               hubdev->max_segment_number = 0xffffffff;
-               hubdev->max_pcibus_number = 0xff;
-               status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev));
-               if (status)
-                       continue;
-
-               /* Save the largest Domain and pcibus numbers found. */
-               if (hubdev->max_segment_number) {
-                       /*
-                        * Dealing with a Prom that supports segments.
-                        */
-                       max_segment_number = hubdev->max_segment_number;
-                       max_pcibus_number = hubdev->max_pcibus_number;
-               }
-               sn_common_hubdev_init(hubdev);
-       }
-}
-
-/*
- * sn_pci_legacy_window_fixup - Setup PCI resources for
- *                             legacy IO and MEM space. This needs to
- *                             be done here, as the PROM does not have
- *                             ACPI support defining the root buses
- *                             and their resources (_CRS),
- */
-static void
-sn_legacy_pci_window_fixup(struct resource *res,
-               u64 legacy_io, u64 legacy_mem)
-{
-               res[0].name = "legacy_io";
-               res[0].flags = IORESOURCE_IO;
-               res[0].start = legacy_io;
-               res[0].end = res[0].start + 0xffff;
-               res[0].parent = &ioport_resource;
-               res[1].name = "legacy_mem";
-               res[1].flags = IORESOURCE_MEM;
-               res[1].start = legacy_mem;
-               res[1].end = res[1].start + (1024 * 1024) - 1;
-               res[1].parent = &iomem_resource;
-}
-
-/*
- * sn_io_slot_fixup() -   We are not running with an ACPI capable PROM,
- *                       and need to convert the pci_dev->resource
- *                       'start' and 'end' addresses to mapped addresses,
- *                       and setup the pci_controller->window array entries.
- */
-void
-sn_io_slot_fixup(struct pci_dev *dev)
-{
-       int idx;
-       struct resource *res;
-       unsigned long size;
-       struct pcidev_info *pcidev_info;
-       struct sn_irq_info *sn_irq_info;
-       int status;
-
-       pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-       if (!pcidev_info)
-               panic("%s: Unable to alloc memory for pcidev_info", __func__);
-
-       sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (!sn_irq_info)
-               panic("%s: Unable to alloc memory for sn_irq_info", __func__);
-
-       /* Call to retrieve pci device information needed by kernel. */
-       status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
-               (u64) dev->bus->number,
-               dev->devfn,
-               (u64) __pa(pcidev_info),
-               (u64) __pa(sn_irq_info));
-
-       BUG_ON(status); /* Cannot get platform pci device information */
-
-
-       /* Copy over PIO Mapped Addresses */
-       for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
-               if (!pcidev_info->pdi_pio_mapped_addr[idx])
-                       continue;
-
-               res = &dev->resource[idx];
-
-               size = res->end - res->start;
-               if (size == 0)
-                       continue;
-
-               res->start = pcidev_info->pdi_pio_mapped_addr[idx];
-               res->end = res->start + size;
-
-               /*
-                * if it's already in the device structure, remove it before
-                * inserting
-                */
-               if (res->parent && res->parent->child)
-                       release_resource(res);
-
-               if (res->flags & IORESOURCE_IO)
-                       insert_resource(&ioport_resource, res);
-               else
-                       insert_resource(&iomem_resource, res);
-               /*
-                * If ROM, mark as shadowed in PROM.
-                */
-               if (idx == PCI_ROM_RESOURCE) {
-                       pci_disable_rom(dev);
-                       res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW |
-                                    IORESOURCE_PCI_FIXED;
-               }
-       }
-
-       sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
-}
-EXPORT_SYMBOL(sn_io_slot_fixup);
-
-/*
- * sn_pci_controller_fixup() - This routine sets up a bus's resources
- *                            consistent with the Linux PCI abstraction layer.
- */
-static void __init
-sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
-{
-       s64 status = 0;
-       struct pci_controller *controller;
-       struct pcibus_bussoft *prom_bussoft_ptr;
-       struct resource *res;
-       LIST_HEAD(resources);
-
-       status = sal_get_pcibus_info((u64) segment, (u64) busnum,
-                                    (u64) ia64_tpa(&prom_bussoft_ptr));
-       if (status > 0)
-               return;         /*bus # does not exist */
-       prom_bussoft_ptr = __va(prom_bussoft_ptr);
-
-       controller = kzalloc(sizeof(*controller), GFP_KERNEL);
-       BUG_ON(!controller);
-       controller->segment = segment;
-
-       res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
-       BUG_ON(!res);
-
-       /*
-        * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup().
-        * (platform_data will be overwritten later in sn_common_bus_fixup())
-        */
-       controller->platform_data = prom_bussoft_ptr;
-
-       sn_legacy_pci_window_fixup(res,
-                       prom_bussoft_ptr->bs_legacy_io,
-                       prom_bussoft_ptr->bs_legacy_mem);
-       pci_add_resource_offset(&resources,     &res[0],
-                       prom_bussoft_ptr->bs_legacy_io);
-       pci_add_resource_offset(&resources,     &res[1],
-                       prom_bussoft_ptr->bs_legacy_mem);
-
-       bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
-                               &resources);
-       if (bus == NULL) {
-               kfree(res);
-               kfree(controller);
-               return;
-       }
-       pci_bus_add_devices(bus);
-}
-
-/*
- * sn_bus_fixup
- */
-void
-sn_bus_fixup(struct pci_bus *bus)
-{
-       struct pci_dev *pci_dev = NULL;
-       struct pcibus_bussoft *prom_bussoft_ptr;
-
-       if (!bus->parent) {  /* If root bus */
-               prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
-               if (prom_bussoft_ptr == NULL) {
-                       printk(KERN_ERR
-                              "sn_bus_fixup: 0x%04x:0x%02x Unable to "
-                              "obtain prom_bussoft_ptr\n",
-                              pci_domain_nr(bus), bus->number);
-                       return;
-               }
-               sn_common_bus_fixup(bus, prom_bussoft_ptr);
-        }
-        list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-                sn_io_slot_fixup(pci_dev);
-        }
-
-}
-
-/*
- * sn_io_init - PROM does not have ACPI support to define nodes or root buses,
- *             so we need to do things the hard way, including initiating the
- *             bus scanning ourselves.
- */
-
-void __init sn_io_init(void)
-{
-       int i, j;
-
-       sn_fixup_ionodes();
-
-       /* busses are not known yet ... */
-       for (i = 0; i <= max_segment_number; i++)
-               for (j = 0; j <= max_pcibus_number; j++)
-                       sn_pci_controller_fixup(i, j, NULL);
-}
diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c
deleted file mode 100644 (file)
index 2b22a71..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2003, 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/vga.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/acpi.h>
-
-#define IS_LEGACY_VGA_IOPORT(p) \
-       (((p) >= 0x3b0 && (p) <= 0x3bb) || ((p) >= 0x3c0 && (p) <= 0x3df))
-
-/**
- * sn_io_addr - convert an in/out port to an i/o address
- * @port: port to convert
- *
- * Legacy in/out instructions are converted to ld/st instructions
- * on IA64.  This routine will convert a port number into a valid
- * SN i/o address.  Used by sn_in*() and sn_out*().
- */
-
-void *sn_io_addr(unsigned long port)
-{
-       if (!IS_RUNNING_ON_SIMULATOR()) {
-               if (IS_LEGACY_VGA_IOPORT(port))
-                       return (__ia64_mk_io_addr(port));
-               /* On sn2, legacy I/O ports don't point at anything */
-               if (port < (64 * 1024))
-                       return NULL;
-               if (SN_ACPI_BASE_SUPPORT())
-                       return (__ia64_mk_io_addr(port));
-               else
-                       return ((void *)(port | __IA64_UNCACHED_OFFSET));
-       } else {
-               /* but the simulator uses them... */
-               unsigned long addr;
-
-               /*
-                * word align port, but need more than 10 bits
-                * for accessing registers in bedrock local block
-                * (so we don't do port&0xfff)
-                */
-               addr = (is_shub2() ? 0xc00000028c000000UL : 0xc0000087cc000000UL) | ((port >> 2) << 12);
-               if ((port >= 0x1f0 && port <= 0x1f7) || port == 0x3f6 || port == 0x3f7)
-                       addr |= port;
-               return (void *)addr;
-       }
-}
-
-EXPORT_SYMBOL(sn_io_addr);
-
-/**
- * __sn_mmiowb - I/O space memory barrier
- *
- * See arch/ia64/include/asm/io.h and Documentation/driver-api/device-io.rst
- * for details.
- *
- * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear.
- * See PV 871084 for details about the WAR about zero value.
- *
- */
-void __sn_mmiowb(void)
-{
-       volatile unsigned long *adr = pda->pio_write_status_addr;
-       unsigned long val = pda->pio_write_status_val;
-
-       while ((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != val)
-               cpu_relax();
-}
-
-EXPORT_SYMBOL(__sn_mmiowb);
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
deleted file mode 100644 (file)
index d9b576d..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Platform dependent support for SGI SN
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000-2008 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/rculist.h>
-#include <linux/slab.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/sn_feature_sets.h>
-
-static void register_intr_pda(struct sn_irq_info *sn_irq_info);
-static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
-
-extern int sn_ioif_inited;
-struct list_head **sn_irq_lh;
-static DEFINE_SPINLOCK(sn_irq_info_lock); /* non-IRQ lock */
-
-u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
-                                    struct sn_irq_info *sn_irq_info,
-                                    int req_irq, nasid_t req_nasid,
-                                    int req_slice)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
-                       (u64) SAL_INTR_ALLOC, (u64) local_nasid,
-                       (u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
-                       (u64) req_nasid, (u64) req_slice);
-
-       return ret_stuff.status;
-}
-
-void sn_intr_free(nasid_t local_nasid, int local_widget,
-                               struct sn_irq_info *sn_irq_info)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
-                       (u64) SAL_INTR_FREE, (u64) local_nasid,
-                       (u64) local_widget, (u64) sn_irq_info->irq_irq,
-                       (u64) sn_irq_info->irq_cookie, 0, 0);
-}
-
-u64 sn_intr_redirect(nasid_t local_nasid, int local_widget,
-                     struct sn_irq_info *sn_irq_info,
-                     nasid_t req_nasid, int req_slice)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
-                       (u64) SAL_INTR_REDIRECT, (u64) local_nasid,
-                       (u64) local_widget, __pa(sn_irq_info),
-                       (u64) req_nasid, (u64) req_slice, 0);
-
-       return ret_stuff.status;
-}
-
-static unsigned int sn_startup_irq(struct irq_data *data)
-{
-       return 0;
-}
-
-static void sn_shutdown_irq(struct irq_data *data)
-{
-}
-
-extern void ia64_mca_register_cpev(int);
-
-static void sn_disable_irq(struct irq_data *data)
-{
-       if (data->irq == local_vector_to_irq(IA64_CPE_VECTOR))
-               ia64_mca_register_cpev(0);
-}
-
-static void sn_enable_irq(struct irq_data *data)
-{
-       if (data->irq == local_vector_to_irq(IA64_CPE_VECTOR))
-               ia64_mca_register_cpev(data->irq);
-}
-
-static void sn_ack_irq(struct irq_data *data)
-{
-       u64 event_occurred, mask;
-       unsigned int irq = data->irq & 0xff;
-
-       event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED));
-       mask = event_occurred & SH_ALL_INT_MASK;
-       HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), mask);
-       __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
-
-       irq_move_irq(data);
-}
-
-struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
-                                      nasid_t nasid, int slice)
-{
-       int vector;
-       int cpuid;
-#ifdef CONFIG_SMP
-       int cpuphys;
-#endif
-       int64_t bridge;
-       int local_widget, status;
-       nasid_t local_nasid;
-       struct sn_irq_info *new_irq_info;
-       struct sn_pcibus_provider *pci_provider;
-
-       bridge = (u64) sn_irq_info->irq_bridge;
-       if (!bridge) {
-               return NULL; /* irq is not a device interrupt */
-       }
-
-       local_nasid = NASID_GET(bridge);
-
-       if (local_nasid & 1)
-               local_widget = TIO_SWIN_WIDGETNUM(bridge);
-       else
-               local_widget = SWIN_WIDGETNUM(bridge);
-       vector = sn_irq_info->irq_irq;
-
-       /* Make use of SAL_INTR_REDIRECT if PROM supports it */
-       status = sn_intr_redirect(local_nasid, local_widget, sn_irq_info, nasid, slice);
-       if (!status) {
-               new_irq_info = sn_irq_info;
-               goto finish_up;
-       }
-
-       /*
-        * PROM does not support SAL_INTR_REDIRECT, or it failed.
-        * Revert to old method.
-        */
-       new_irq_info = kmemdup(sn_irq_info, sizeof(struct sn_irq_info),
-                              GFP_ATOMIC);
-       if (new_irq_info == NULL)
-               return NULL;
-
-       /* Free the old PROM new_irq_info structure */
-       sn_intr_free(local_nasid, local_widget, new_irq_info);
-       unregister_intr_pda(new_irq_info);
-
-       /* allocate a new PROM new_irq_info struct */
-       status = sn_intr_alloc(local_nasid, local_widget,
-                              new_irq_info, vector,
-                              nasid, slice);
-
-       /* SAL call failed */
-       if (status) {
-               kfree(new_irq_info);
-               return NULL;
-       }
-
-       register_intr_pda(new_irq_info);
-       spin_lock(&sn_irq_info_lock);
-       list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
-       spin_unlock(&sn_irq_info_lock);
-       kfree_rcu(sn_irq_info, rcu);
-
-
-finish_up:
-       /* Update kernels new_irq_info with new target info */
-       cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid,
-                                    new_irq_info->irq_slice);
-       new_irq_info->irq_cpuid = cpuid;
-
-       pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
-
-       /*
-        * If this represents a line interrupt, target it.  If it's
-        * an msi (irq_int_bit < 0), it's already targeted.
-        */
-       if (new_irq_info->irq_int_bit >= 0 &&
-           pci_provider && pci_provider->target_interrupt)
-               (pci_provider->target_interrupt)(new_irq_info);
-
-#ifdef CONFIG_SMP
-       cpuphys = cpu_physical_id(cpuid);
-       set_irq_affinity_info((vector & 0xff), cpuphys, 0);
-#endif
-
-       return new_irq_info;
-}
-
-static int sn_set_affinity_irq(struct irq_data *data,
-                              const struct cpumask *mask, bool force)
-{
-       struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
-       unsigned int irq = data->irq;
-       nasid_t nasid;
-       int slice;
-
-       nasid = cpuid_to_nasid(cpumask_first_and(mask, cpu_online_mask));
-       slice = cpuid_to_slice(cpumask_first_and(mask, cpu_online_mask));
-
-       list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
-                                sn_irq_lh[irq], list)
-               (void)sn_retarget_vector(sn_irq_info, nasid, slice);
-
-       return 0;
-}
-
-#ifdef CONFIG_SMP
-void sn_set_err_irq_affinity(unsigned int irq)
-{
-        /*
-         * On systems which support CPU disabling (SHub2), all error interrupts
-         * are targeted at the boot CPU.
-         */
-        if (is_shub2() && sn_prom_feature_available(PRF_CPU_DISABLE_SUPPORT))
-                set_irq_affinity_info(irq, cpu_physical_id(0), 0);
-}
-#else
-void sn_set_err_irq_affinity(unsigned int irq) { }
-#endif
-
-static void
-sn_mask_irq(struct irq_data *data)
-{
-}
-
-static void
-sn_unmask_irq(struct irq_data *data)
-{
-}
-
-struct irq_chip irq_type_sn = {
-       .name                   = "SN hub",
-       .irq_startup            = sn_startup_irq,
-       .irq_shutdown           = sn_shutdown_irq,
-       .irq_enable             = sn_enable_irq,
-       .irq_disable            = sn_disable_irq,
-       .irq_ack                = sn_ack_irq,
-       .irq_mask               = sn_mask_irq,
-       .irq_unmask             = sn_unmask_irq,
-       .irq_set_affinity       = sn_set_affinity_irq
-};
-
-ia64_vector sn_irq_to_vector(int irq)
-{
-       if (irq >= IA64_NUM_VECTORS)
-               return 0;
-       return (ia64_vector)irq;
-}
-
-unsigned int sn_local_vector_to_irq(u8 vector)
-{
-       return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
-}
-
-void sn_irq_init(void)
-{
-       int i;
-
-       ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
-       ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
-
-       for (i = 0; i < NR_IRQS; i++) {
-               if (irq_get_chip(i) == &no_irq_chip)
-                       irq_set_chip(i, &irq_type_sn);
-       }
-}
-
-static void register_intr_pda(struct sn_irq_info *sn_irq_info)
-{
-       int irq = sn_irq_info->irq_irq;
-       int cpu = sn_irq_info->irq_cpuid;
-
-       if (pdacpu(cpu)->sn_last_irq < irq) {
-               pdacpu(cpu)->sn_last_irq = irq;
-       }
-
-       if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq)
-               pdacpu(cpu)->sn_first_irq = irq;
-}
-
-static void unregister_intr_pda(struct sn_irq_info *sn_irq_info)
-{
-       int irq = sn_irq_info->irq_irq;
-       int cpu = sn_irq_info->irq_cpuid;
-       struct sn_irq_info *tmp_irq_info;
-       int i, foundmatch;
-
-       rcu_read_lock();
-       if (pdacpu(cpu)->sn_last_irq == irq) {
-               foundmatch = 0;
-               for (i = pdacpu(cpu)->sn_last_irq - 1;
-                    i && !foundmatch; i--) {
-                       list_for_each_entry_rcu(tmp_irq_info,
-                                               sn_irq_lh[i],
-                                               list) {
-                               if (tmp_irq_info->irq_cpuid == cpu) {
-                                       foundmatch = 1;
-                                       break;
-                               }
-                       }
-               }
-               pdacpu(cpu)->sn_last_irq = i;
-       }
-
-       if (pdacpu(cpu)->sn_first_irq == irq) {
-               foundmatch = 0;
-               for (i = pdacpu(cpu)->sn_first_irq + 1;
-                    i < NR_IRQS && !foundmatch; i++) {
-                       list_for_each_entry_rcu(tmp_irq_info,
-                                               sn_irq_lh[i],
-                                               list) {
-                               if (tmp_irq_info->irq_cpuid == cpu) {
-                                       foundmatch = 1;
-                                       break;
-                               }
-                       }
-               }
-               pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i);
-       }
-       rcu_read_unlock();
-}
-
-void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
-{
-       nasid_t nasid = sn_irq_info->irq_nasid;
-       int slice = sn_irq_info->irq_slice;
-       int cpu = nasid_slice_to_cpuid(nasid, slice);
-#ifdef CONFIG_SMP
-       int cpuphys;
-#endif
-
-       pci_dev_get(pci_dev);
-       sn_irq_info->irq_cpuid = cpu;
-       sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
-
-       /* link it into the sn_irq[irq] list */
-       spin_lock(&sn_irq_info_lock);
-       list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
-       reserve_irq_vector(sn_irq_info->irq_irq);
-       if (sn_irq_info->irq_int_bit != -1)
-               irq_set_handler(sn_irq_info->irq_irq, handle_level_irq);
-       spin_unlock(&sn_irq_info_lock);
-
-       register_intr_pda(sn_irq_info);
-#ifdef CONFIG_SMP
-       cpuphys = cpu_physical_id(cpu);
-       set_irq_affinity_info(sn_irq_info->irq_irq, cpuphys, 0);
-       /*
-        * Affinity was set by the PROM, prevent it from
-        * being reset by the request_irq() path.
-        */
-       irqd_mark_affinity_was_set(irq_get_irq_data(sn_irq_info->irq_irq));
-#endif
-}
-
-void sn_irq_unfixup(struct pci_dev *pci_dev)
-{
-       struct sn_irq_info *sn_irq_info;
-
-       /* Only cleanup IRQ stuff if this device has a host bus context */
-       if (!SN_PCIDEV_BUSSOFT(pci_dev))
-               return;
-
-       sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info;
-       if (!sn_irq_info)
-               return;
-       if (!sn_irq_info->irq_irq) {
-               kfree(sn_irq_info);
-               return;
-       }
-
-       unregister_intr_pda(sn_irq_info);
-       spin_lock(&sn_irq_info_lock);
-       list_del_rcu(&sn_irq_info->list);
-       spin_unlock(&sn_irq_info_lock);
-       if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
-               free_irq_vector(sn_irq_info->irq_irq);
-       kfree_rcu(sn_irq_info, rcu);
-       pci_dev_put(pci_dev);
-
-}
-
-static inline void
-sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info)
-{
-       struct sn_pcibus_provider *pci_provider;
-
-       pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type];
-
-       /* Don't force an interrupt if the irq has been disabled */
-       if (!irqd_irq_disabled(irq_get_irq_data(sn_irq_info->irq_irq)) &&
-           pci_provider && pci_provider->force_interrupt)
-               (*pci_provider->force_interrupt)(sn_irq_info);
-}
-
-/*
- * Check for lost interrupts.  If the PIC int_status reg. says that
- * an interrupt has been sent, but not handled, and the interrupt
- * is not pending in either the cpu irr regs or in the soft irr regs,
- * and the interrupt is not in service, then the interrupt may have
- * been lost.  Force an interrupt on that pin.  It is possible that
- * the interrupt is in flight, so we may generate a spurious interrupt,
- * but we should never miss a real lost interrupt.
- */
-static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
-{
-       u64 regval;
-       struct pcidev_info *pcidev_info;
-       struct pcibus_info *pcibus_info;
-
-       /*
-        * Bridge types attached to TIO (anything but PIC) do not need this WAR
-        * since they do not target Shub II interrupt registers.  If that
-        * ever changes, this check needs to accommodate.
-        */
-       if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC)
-               return;
-
-       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       if (!pcidev_info)
-               return;
-
-       pcibus_info =
-           (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
-           pdi_pcibus_info;
-       regval = pcireg_intr_status_get(pcibus_info);
-
-       if (!ia64_get_irr(irq_to_vector(irq))) {
-               if (!test_bit(irq, pda->sn_in_service_ivecs)) {
-                       regval &= 0xff;
-                       if (sn_irq_info->irq_int_bit & regval &
-                           sn_irq_info->irq_last_intr) {
-                               regval &= ~(sn_irq_info->irq_int_bit & regval);
-                               sn_call_force_intr_provider(sn_irq_info);
-                       }
-               }
-       }
-       sn_irq_info->irq_last_intr = regval;
-}
-
-void sn_lb_int_war_check(void)
-{
-       struct sn_irq_info *sn_irq_info;
-       int i;
-
-       if (!sn_ioif_inited || pda->sn_first_irq == 0)
-               return;
-
-       rcu_read_lock();
-       for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
-               list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
-                       sn_check_intr(i, sn_irq_info);
-               }
-       }
-       rcu_read_unlock();
-}
-
-void __init sn_irq_lh_init(void)
-{
-       int i;
-
-       sn_irq_lh = kmalloc_array(NR_IRQS, sizeof(struct list_head *),
-                                 GFP_KERNEL);
-       if (!sn_irq_lh)
-               panic("SN PCI INIT: Failed to allocate memory for PCI init\n");
-
-       for (i = 0; i < NR_IRQS; i++) {
-               sn_irq_lh[i] = kmalloc(sizeof(struct list_head), GFP_KERNEL);
-               if (!sn_irq_lh[i])
-                       panic("SN PCI INIT: Failed IRQ memory allocation\n");
-
-               INIT_LIST_HEAD(sn_irq_lh[i]);
-       }
-}
diff --git a/arch/ia64/sn/kernel/klconflib.c b/arch/ia64/sn/kernel/klconflib.c
deleted file mode 100644 (file)
index 87682b4..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <asm/sn/types.h>
-#include <asm/sn/module.h>
-#include <asm/sn/l1.h>
-
-char brick_types[MAX_BRICK_TYPES + 1] = "cri.xdpn%#=vo^kjbf890123456789...";
-/*
- * Format a module id for printing.
- *
- * There are three possible formats:
- *
- *   MODULE_FORMAT_BRIEF       is the brief 6-character format, including
- *                             the actual brick-type as recorded in the 
- *                             moduleid_t, eg. 002c15 for a C-brick, or
- *                             101#17 for a PX-brick.
- *
- *   MODULE_FORMAT_LONG                is the hwgraph format, eg. rack/002/bay/15
- *                             of rack/101/bay/17 (note that the brick
- *                             type does not appear in this format).
- *
- *   MODULE_FORMAT_LCD         is like MODULE_FORMAT_BRIEF, except that it
- *                             ensures that the module id provided appears
- *                             exactly as it would on the LCD display of
- *                             the corresponding brick, eg. still 002c15
- *                             for a C-brick, but 101p17 for a PX-brick.
- *
- * maule (9/13/04):  Removed top-level check for (fmt == MODULE_FORMAT_LCD)
- * making MODULE_FORMAT_LCD equivalent to MODULE_FORMAT_BRIEF.  It was
- * decided that all callers should assume the returned string should be what
- * is displayed on the brick L1 LCD.
- */
-void
-format_module_id(char *buffer, moduleid_t m, int fmt)
-{
-       int rack, position;
-       unsigned char brickchar;
-
-       rack = MODULE_GET_RACK(m);
-       brickchar = MODULE_GET_BTCHAR(m);
-
-       /* Be sure we use the same brick type character as displayed
-        * on the brick's LCD
-        */
-       switch (brickchar) 
-       {
-       case L1_BRICKTYPE_GA:
-       case L1_BRICKTYPE_OPUS_TIO:
-               brickchar = L1_BRICKTYPE_C;
-               break;
-
-       case L1_BRICKTYPE_PX:
-       case L1_BRICKTYPE_PE:
-       case L1_BRICKTYPE_PA:
-       case L1_BRICKTYPE_SA: /* we can move this to the "I's" later
-                              * if that makes more sense
-                              */
-               brickchar = L1_BRICKTYPE_P;
-               break;
-
-       case L1_BRICKTYPE_IX:
-       case L1_BRICKTYPE_IA:
-
-               brickchar = L1_BRICKTYPE_I;
-               break;
-       }
-
-       position = MODULE_GET_BPOS(m);
-
-       if ((fmt == MODULE_FORMAT_BRIEF) || (fmt == MODULE_FORMAT_LCD)) {
-               /* Brief module number format, eg. 002c15 */
-
-               /* Decompress the rack number */
-               *buffer++ = '0' + RACK_GET_CLASS(rack);
-               *buffer++ = '0' + RACK_GET_GROUP(rack);
-               *buffer++ = '0' + RACK_GET_NUM(rack);
-
-               /* Add the brick type */
-               *buffer++ = brickchar;
-       }
-       else if (fmt == MODULE_FORMAT_LONG) {
-               /* Fuller hwgraph format, eg. rack/002/bay/15 */
-
-               strcpy(buffer, "rack" "/");  buffer += strlen(buffer);
-
-               *buffer++ = '0' + RACK_GET_CLASS(rack);
-               *buffer++ = '0' + RACK_GET_GROUP(rack);
-               *buffer++ = '0' + RACK_GET_NUM(rack);
-
-               strcpy(buffer, "/" "bay" "/");  buffer += strlen(buffer);
-       }
-
-       /* Add the bay position, using at least two digits */
-       if (position < 10)
-               *buffer++ = '0';
-       sprintf(buffer, "%d", position);
-}
diff --git a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c
deleted file mode 100644 (file)
index 02bb915..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2002-2003 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#define MACHVEC_PLATFORM_NAME  sn2
-#define MACHVEC_PLATFORM_HEADER        <asm/machvec_sn2.h>
-#include <asm/machvec_init.h>
diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
deleted file mode 100644 (file)
index bc3bd93..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/vmalloc.h>
-#include <linux/mutex.h>
-#include <asm/mca.h>
-#include <asm/sal.h>
-#include <asm/sn/sn_sal.h>
-
-/*
- * Interval for calling SAL to poll for errors that do NOT cause error
- * interrupts. SAL will raise a CPEI if any errors are present that
- * need to be logged.
- */
-#define CPEI_INTERVAL  (5*HZ)
-
-struct timer_list sn_cpei_timer;
-void sn_init_cpei_timer(void);
-
-/* Printing oemdata from mca uses data that is not passed through SAL, it is
- * global.  Only one user at a time.
- */
-static DEFINE_MUTEX(sn_oemdata_mutex);
-static u8 **sn_oemdata;
-static u64 *sn_oemdata_size, sn_oemdata_bufsize;
-
-/*
- * print_hook
- *
- * This function is the callback routine that SAL calls to log error
- * info for platform errors.  buf is appended to sn_oemdata, resizing as
- * required.
- * Note: this is a SAL to OS callback, running under the same rules as the SAL
- * code.  SAL calls are run with preempt disabled so this routine must not
- * sleep.  vmalloc can sleep so print_hook cannot resize the output buffer
- * itself, instead it must set the required size and return to let the caller
- * resize the buffer then redrive the SAL call.
- */
-static int print_hook(const char *fmt, ...)
-{
-       char buf[400];
-       int len;
-       va_list args;
-       va_start(args, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
-       len = strlen(buf);
-       if (*sn_oemdata_size + len <= sn_oemdata_bufsize)
-               memcpy(*sn_oemdata + *sn_oemdata_size, buf, len);
-       *sn_oemdata_size += len;
-       return 0;
-}
-
-static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
-{
-       /*
-        * this function's sole purpose is to call SAL when we receive
-        * a CE interrupt from SHUB or when the timer routine decides
-        * we need to call SAL to check for CEs.
-        */
-
-       /* CALL SAL_LOG_CE */
-
-       ia64_sn_plat_cpei_handler();
-}
-
-static void sn_cpei_timer_handler(struct timer_list *unused)
-{
-       sn_cpei_handler(-1, NULL, NULL);
-       mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL);
-}
-
-void sn_init_cpei_timer(void)
-{
-       timer_setup(&sn_cpei_timer, sn_cpei_timer_handler, 0);
-       sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
-       add_timer(&sn_cpei_timer);
-}
-
-static int
-sn_platform_plat_specific_err_print(const u8 * sect_header, u8 ** oemdata,
-                                   u64 * oemdata_size)
-{
-       mutex_lock(&sn_oemdata_mutex);
-       sn_oemdata = oemdata;
-       sn_oemdata_size = oemdata_size;
-       sn_oemdata_bufsize = 0;
-       *sn_oemdata_size = PAGE_SIZE;   /* first guess at how much data will be generated */
-       while (*sn_oemdata_size > sn_oemdata_bufsize) {
-               u8 *newbuf = vmalloc(*sn_oemdata_size);
-               if (!newbuf) {
-                       mutex_unlock(&sn_oemdata_mutex);
-                       printk(KERN_ERR "%s: unable to extend sn_oemdata\n",
-                              __func__);
-                       return 1;
-               }
-               vfree(*sn_oemdata);
-               *sn_oemdata = newbuf;
-               sn_oemdata_bufsize = *sn_oemdata_size;
-               *sn_oemdata_size = 0;
-               ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header);
-       }
-       mutex_unlock(&sn_oemdata_mutex);
-       return 0;
-}
-
-/* Callback when userspace salinfo wants to decode oem data via the platform
- * kernel and/or prom.
- */
-int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size)
-{
-       efi_guid_t guid = *(efi_guid_t *)sect_header;
-       int valid = 0;
-       *oemdata_size = 0;
-       vfree(*oemdata);
-       *oemdata = NULL;
-       if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
-               sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header;
-               valid = psei->valid.oem_data;
-       } else if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
-               sal_log_mem_dev_err_info_t *mdei = (sal_log_mem_dev_err_info_t *)sect_header;
-               valid = mdei->valid.oem_data;
-       }
-       if (valid)
-               return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size);
-       else
-               return 0;
-}
-
-static int __init sn_salinfo_init(void)
-{
-       if (ia64_platform_is("sn2"))
-               salinfo_platform_oemdata = &sn_salinfo_platform_oemdata;
-       return 0;
-}
-device_initcall(sn_salinfo_init);
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
deleted file mode 100644 (file)
index fb25065..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/cpumask.h>
-#include <linux/msi.h>
-#include <linux/slab.h>
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/nodepda.h>
-
-struct sn_msi_info {
-       u64 pci_addr;
-       struct sn_irq_info *sn_irq_info;
-};
-
-static struct sn_msi_info sn_msi_info[NR_IRQS];
-
-static struct irq_chip sn_msi_chip;
-
-void sn_teardown_msi_irq(unsigned int irq)
-{
-       nasid_t nasid;
-       int widget;
-       struct pci_dev *pdev;
-       struct pcidev_info *sn_pdev;
-       struct sn_irq_info *sn_irq_info;
-       struct pcibus_bussoft *bussoft;
-       struct sn_pcibus_provider *provider;
-
-       sn_irq_info = sn_msi_info[irq].sn_irq_info;
-       if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
-               return;
-
-       sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       pdev = sn_pdev->pdi_linux_pcidev;
-       provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       (*provider->dma_unmap)(pdev,
-                              sn_msi_info[irq].pci_addr,
-                              PCI_DMA_FROMDEVICE);
-       sn_msi_info[irq].pci_addr = 0;
-
-       bussoft = SN_PCIDEV_BUSSOFT(pdev);
-       nasid = NASID_GET(bussoft->bs_base);
-       widget = (nasid & 1) ?
-                       TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
-                       SWIN_WIDGETNUM(bussoft->bs_base);
-
-       sn_intr_free(nasid, widget, sn_irq_info);
-       sn_msi_info[irq].sn_irq_info = NULL;
-
-       destroy_irq(irq);
-}
-
-int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
-{
-       struct msi_msg msg;
-       int widget;
-       int status;
-       nasid_t nasid;
-       u64 bus_addr;
-       struct sn_irq_info *sn_irq_info;
-       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-       int irq;
-
-       if (!entry->msi_attrib.is_64)
-               return -EINVAL;
-
-       if (bussoft == NULL)
-               return -EINVAL;
-
-       if (provider == NULL || provider->dma_map_consistent == NULL)
-               return -EINVAL;
-
-       irq = create_irq();
-       if (irq < 0)
-               return irq;
-
-       /*
-        * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
-        * decide which cpu to direct this msi at by default.
-        */
-
-       nasid = NASID_GET(bussoft->bs_base);
-       widget = (nasid & 1) ?
-                       TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
-                       SWIN_WIDGETNUM(bussoft->bs_base);
-
-       sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (! sn_irq_info) {
-               destroy_irq(irq);
-               return -ENOMEM;
-       }
-
-       status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
-       if (status) {
-               kfree(sn_irq_info);
-               destroy_irq(irq);
-               return -ENOMEM;
-       }
-
-       sn_irq_info->irq_int_bit = -1;          /* mark this as an MSI irq */
-       sn_irq_fixup(pdev, sn_irq_info);
-
-       /* Prom probably should fill these in, but doesn't ... */
-       sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
-       sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
-
-       /*
-        * Map the xio address into bus space
-        */
-       bus_addr = (*provider->dma_map_consistent)(pdev,
-                                       sn_irq_info->irq_xtalkaddr,
-                                       sizeof(sn_irq_info->irq_xtalkaddr),
-                                       SN_DMA_MSI|SN_DMA_ADDR_XIO);
-       if (! bus_addr) {
-               sn_intr_free(nasid, widget, sn_irq_info);
-               kfree(sn_irq_info);
-               destroy_irq(irq);
-               return -ENOMEM;
-       }
-
-       sn_msi_info[irq].sn_irq_info = sn_irq_info;
-       sn_msi_info[irq].pci_addr = bus_addr;
-
-       msg.address_hi = (u32)(bus_addr >> 32);
-       msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
-
-       /*
-        * In the SN platform, bit 16 is a "send vector" bit which
-        * must be present in order to move the vector through the system.
-        */
-       msg.data = 0x100 + irq;
-
-       irq_set_msi_desc(irq, entry);
-       pci_write_msi_msg(irq, &msg);
-       irq_set_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
-
-       return 0;
-}
-
-#ifdef CONFIG_SMP
-static int sn_set_msi_irq_affinity(struct irq_data *data,
-                                  const struct cpumask *cpu_mask, bool force)
-{
-       struct msi_msg msg;
-       int slice;
-       nasid_t nasid;
-       u64 bus_addr;
-       struct pci_dev *pdev;
-       struct pcidev_info *sn_pdev;
-       struct sn_irq_info *sn_irq_info;
-       struct sn_irq_info *new_irq_info;
-       struct sn_pcibus_provider *provider;
-       unsigned int cpu, irq = data->irq;
-
-       cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
-       sn_irq_info = sn_msi_info[irq].sn_irq_info;
-       if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
-               return -1;
-
-       /*
-        * Release XIO resources for the old MSI PCI address
-        */
-
-       __get_cached_msi_msg(irq_data_get_msi_desc(data), &msg);
-       sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       pdev = sn_pdev->pdi_linux_pcidev;
-       provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
-       (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
-       sn_msi_info[irq].pci_addr = 0;
-
-       nasid = cpuid_to_nasid(cpu);
-       slice = cpuid_to_slice(cpu);
-
-       new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
-       sn_msi_info[irq].sn_irq_info = new_irq_info;
-       if (new_irq_info == NULL)
-               return -1;
-
-       /*
-        * Map the xio address into bus space
-        */
-
-       bus_addr = (*provider->dma_map_consistent)(pdev,
-                                       new_irq_info->irq_xtalkaddr,
-                                       sizeof(new_irq_info->irq_xtalkaddr),
-                                       SN_DMA_MSI|SN_DMA_ADDR_XIO);
-
-       sn_msi_info[irq].pci_addr = bus_addr;
-       msg.address_hi = (u32)(bus_addr >> 32);
-       msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
-
-       pci_write_msi_msg(irq, &msg);
-       cpumask_copy(irq_data_get_affinity_mask(data), cpu_mask);
-
-       return 0;
-}
-#endif /* CONFIG_SMP */
-
-static void sn_ack_msi_irq(struct irq_data *data)
-{
-       irq_move_irq(data);
-       ia64_eoi();
-}
-
-static int sn_msi_retrigger_irq(struct irq_data *data)
-{
-       unsigned int vector = data->irq;
-       ia64_resend_irq(vector);
-
-       return 1;
-}
-
-static struct irq_chip sn_msi_chip = {
-       .name                   = "PCI-MSI",
-       .irq_mask               = pci_msi_mask_irq,
-       .irq_unmask             = pci_msi_unmask_irq,
-       .irq_ack                = sn_ack_msi_irq,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       = sn_set_msi_irq_affinity,
-#endif
-       .irq_retrigger          = sn_msi_retrigger_irq,
-};
diff --git a/arch/ia64/sn/kernel/pio_phys.S b/arch/ia64/sn/kernel/pio_phys.S
deleted file mode 100644 (file)
index 3c7d48d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
- *
- * This file contains macros used to access MMR registers via
- * uncached physical addresses.
- *      pio_phys_read_mmr  - read an MMR
- *      pio_phys_write_mmr - write an MMR
- *      pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0
- *              Second MMR will be skipped if address is NULL
- *
- * Addresses passed to these routines should be uncached physical addresses
- *     ie., 0x80000....
- */
-
-
-
-#include <asm/asmmacro.h>
-#include <asm/page.h>
-
-GLOBAL_ENTRY(pio_phys_read_mmr)
-       .prologue
-       .regstk 1,0,0,0
-       .body
-       mov r2=psr
-       rsm psr.i | psr.dt
-       ;;
-       srlz.d
-       ld8.acq r8=[r32]
-       ;;
-       mov psr.l=r2;;
-       srlz.d
-       br.ret.sptk.many rp
-END(pio_phys_read_mmr)
-
-GLOBAL_ENTRY(pio_phys_write_mmr)
-       .prologue
-       .regstk 2,0,0,0
-       .body
-       mov r2=psr
-       rsm psr.i | psr.dt
-       ;;
-       srlz.d
-       st8.rel [r32]=r33
-       ;;
-       mov psr.l=r2;;
-       srlz.d
-       br.ret.sptk.many rp
-END(pio_phys_write_mmr)
-
-GLOBAL_ENTRY(pio_atomic_phys_write_mmrs)
-       .prologue
-       .regstk 4,0,0,0
-       .body
-       mov r2=psr
-       cmp.ne p9,p0=r34,r0;
-       rsm psr.i | psr.dt | psr.ic
-       ;;
-       srlz.d
-       st8.rel [r32]=r33
-(p9)   st8.rel [r34]=r35
-       ;;
-       mov psr.l=r2;;
-       srlz.d
-       br.ret.sptk.many rp
-END(pio_atomic_phys_write_mmrs)
-
-
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
deleted file mode 100644 (file)
index e6a5049..0000000
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999,2001-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/kdev_t.h>
-#include <linux/string.h>
-#include <linux/screen_info.h>
-#include <linux/console.h>
-#include <linux/timex.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/serial.h>
-#include <linux/irq.h>
-#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/interrupt.h>
-#include <linux/acpi.h>
-#include <linux/compiler.h>
-#include <linux/root_dev.h>
-#include <linux/nodemask.h>
-#include <linux/pm.h>
-#include <linux/efi.h>
-
-#include <asm/io.h>
-#include <asm/sal.h>
-#include <asm/machvec.h>
-#include <asm/processor.h>
-#include <asm/vga.h>
-#include <asm/setup.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/leds.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/clksupport.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/sn_feature_sets.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-#include <asm/sn/klconfig.h>
-
-
-DEFINE_PER_CPU(struct pda_s, pda_percpu);
-
-#define MAX_PHYS_MEMORY                (1UL << IA64_MAX_PHYS_BITS)     /* Max physical address supported */
-
-extern void bte_init_node(nodepda_t *, cnodeid_t);
-
-extern void sn_timer_init(void);
-extern unsigned long last_time_offset;
-extern void (*ia64_mark_idle) (int);
-extern void snidle(int);
-
-unsigned long sn_rtc_cycles_per_second;
-EXPORT_SYMBOL(sn_rtc_cycles_per_second);
-
-DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
-EXPORT_PER_CPU_SYMBOL(__sn_hub_info);
-
-DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
-EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
-
-DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
-EXPORT_PER_CPU_SYMBOL(__sn_nodepda);
-
-char sn_system_serial_number_string[128];
-EXPORT_SYMBOL(sn_system_serial_number_string);
-u64 sn_partition_serial_number;
-EXPORT_SYMBOL(sn_partition_serial_number);
-u8 sn_partition_id;
-EXPORT_SYMBOL(sn_partition_id);
-u8 sn_system_size;
-EXPORT_SYMBOL(sn_system_size);
-u8 sn_sharing_domain_size;
-EXPORT_SYMBOL(sn_sharing_domain_size);
-u8 sn_coherency_id;
-EXPORT_SYMBOL(sn_coherency_id);
-u8 sn_region_size;
-EXPORT_SYMBOL(sn_region_size);
-int sn_prom_type;      /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
-
-short physical_node_map[MAX_NUMALINK_NODES];
-static unsigned long sn_prom_features[MAX_PROM_FEATURE_SETS];
-
-EXPORT_SYMBOL(physical_node_map);
-
-int num_cnodes;
-
-static void sn_init_pdas(char **);
-static void build_cnode_tables(void);
-
-static nodepda_t *nodepdaindr[MAX_COMPACT_NODES];
-
-/*
- * The format of "screen_info" is strange, and due to early i386-setup
- * code. This is just enough to make the console code think we're on a
- * VGA color display.
- */
-struct screen_info sn_screen_info = {
-       .orig_x = 0,
-       .orig_y = 0,
-       .orig_video_mode = 3,
-       .orig_video_cols = 80,
-       .orig_video_ega_bx = 3,
-       .orig_video_lines = 25,
-       .orig_video_isVGA = 1,
-       .orig_video_points = 16
-};
-
-/*
- * This routine can only be used during init, since
- * smp_boot_data is an init data structure.
- * We have to use smp_boot_data.cpu_phys_id to find
- * the physical id of the processor because the normal
- * cpu_physical_id() relies on data structures that
- * may not be initialized yet.
- */
-
-static int __init pxm_to_nasid(int pxm)
-{
-       int i;
-       int nid;
-
-       nid = pxm_to_node(pxm);
-       for (i = 0; i < num_node_memblks; i++) {
-               if (node_memblk[i].nid == nid) {
-                       return NASID_GET(node_memblk[i].start_paddr);
-               }
-       }
-       return -1;
-}
-
-/**
- * early_sn_setup - early setup routine for SN platforms
- *
- * Sets up an initial console to aid debugging.  Intended primarily
- * for bringup.  See start_kernel() in init/main.c.
- */
-
-void __init early_sn_setup(void)
-{
-       efi_system_table_t *efi_systab;
-       efi_config_table_t *config_tables;
-       struct ia64_sal_systab *sal_systab;
-       struct ia64_sal_desc_entry_point *ep;
-       char *p;
-       int i, j;
-
-       /*
-        * Parse enough of the SAL tables to locate the SAL entry point. Since, console
-        * IO on SN2 is done via SAL calls, early_printk won't work without this.
-        *
-        * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c.
-        * Any changes to those file may have to be made here as well.
-        */
-       efi_systab = (efi_system_table_t *) __va(ia64_boot_param->efi_systab);
-       config_tables = __va(efi_systab->tables);
-       for (i = 0; i < efi_systab->nr_tables; i++) {
-               if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) ==
-                   0) {
-                       sal_systab = __va(config_tables[i].table);
-                       p = (char *)(sal_systab + 1);
-                       for (j = 0; j < sal_systab->entry_count; j++) {
-                               if (*p == SAL_DESC_ENTRY_POINT) {
-                                       ep = (struct ia64_sal_desc_entry_point
-                                             *)p;
-                                       ia64_sal_handler_init(__va
-                                                             (ep->sal_proc),
-                                                             __va(ep->gp));
-                                       return;
-                               }
-                               p += SAL_DESC_SIZE(*p);
-                       }
-               }
-       }
-       /* Uh-oh, SAL not available?? */
-       printk(KERN_ERR "failed to find SAL entry point\n");
-}
-
-extern int platform_intr_list[];
-static int shub_1_1_found;
-
-/*
- * sn_check_for_wars
- *
- * Set flag for enabling shub specific wars
- */
-
-static inline int is_shub_1_1(int nasid)
-{
-       unsigned long id;
-       int rev;
-
-       if (is_shub2())
-               return 0;
-       id = REMOTE_HUB_L(nasid, SH1_SHUB_ID);
-       rev = (id & SH1_SHUB_ID_REVISION_MASK) >> SH1_SHUB_ID_REVISION_SHFT;
-       return rev <= 2;
-}
-
-static void sn_check_for_wars(void)
-{
-       int cnode;
-
-       if (is_shub2()) {
-               /* none yet */
-       } else {
-               for_each_online_node(cnode) {
-                       if (is_shub_1_1(cnodeid_to_nasid(cnode)))
-                               shub_1_1_found = 1;
-               }
-       }
-}
-
-/*
- * Scan the EFI PCDP table (if it exists) for an acceptable VGA console
- * output device.  If one exists, pick it and set sn_legacy_{io,mem} to
- * reflect the bus offsets needed to address it.
- *
- * Since pcdp support in SN is not supported in the 2.4 kernel (or at least
- * the one lbs is based on) just declare the needed structs here.
- *
- * Reference spec http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
- *
- * Returns 0 if no acceptable vga is found, !0 otherwise.
- *
- * Note:  This stuff is duped here because Altix requires the PCDP to
- * locate a usable VGA device due to lack of proper ACPI support.  Structures
- * could be used from drivers/firmware/pcdp.h, but it was decided that moving
- * this file to a more public location just for Altix use was undesirable.
- */
-
-struct hcdp_uart_desc {
-       u8      pad[45];
-};
-
-struct pcdp {
-       u8      signature[4];   /* should be 'HCDP' */
-       u32     length;
-       u8      rev;            /* should be >=3 for pcdp, <3 for hcdp */
-       u8      sum;
-       u8      oem_id[6];
-       u64     oem_tableid;
-       u32     oem_rev;
-       u32     creator_id;
-       u32     creator_rev;
-       u32     num_type0;
-       struct hcdp_uart_desc uart[0];  /* num_type0 of these */
-       /* pcdp descriptors follow */
-}  __attribute__((packed));
-
-struct pcdp_device_desc {
-       u8      type;
-       u8      primary;
-       u16     length;
-       u16     index;
-       /* interconnect specific structure follows */
-       /* device specific structure follows that */
-}  __attribute__((packed));
-
-struct pcdp_interface_pci {
-       u8      type;           /* 1 == pci */
-       u8      reserved;
-       u16     length;
-       u8      segment;
-       u8      bus;
-       u8      dev;
-       u8      fun;
-       u16     devid;
-       u16     vendid;
-       u32     acpi_interrupt;
-       u64     mmio_tra;
-       u64     ioport_tra;
-       u8      flags;
-       u8      translation;
-}  __attribute__((packed));
-
-struct pcdp_vga_device {
-       u8      num_eas_desc;
-       /* ACPI Extended Address Space Desc follows */
-}  __attribute__((packed));
-
-/* from pcdp_device_desc.primary */
-#define PCDP_PRIMARY_CONSOLE   0x01
-
-/* from pcdp_device_desc.type */
-#define PCDP_CONSOLE_INOUT     0x0
-#define PCDP_CONSOLE_DEBUG     0x1
-#define PCDP_CONSOLE_OUT       0x2
-#define PCDP_CONSOLE_IN                0x3
-#define PCDP_CONSOLE_TYPE_VGA  0x8
-
-#define PCDP_CONSOLE_VGA       (PCDP_CONSOLE_TYPE_VGA | PCDP_CONSOLE_OUT)
-
-/* from pcdp_interface_pci.type */
-#define PCDP_IF_PCI            1
-
-/* from pcdp_interface_pci.translation */
-#define PCDP_PCI_TRANS_IOPORT  0x02
-#define PCDP_PCI_TRANS_MMIO    0x01
-
-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
-static void
-sn_scan_pcdp(void)
-{
-       u8 *bp;
-       struct pcdp *pcdp;
-       struct pcdp_device_desc device;
-       struct pcdp_interface_pci if_pci;
-       extern struct efi efi;
-
-       if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
-               return;         /* no hcdp/pcdp table */
-
-       pcdp = __va(efi.hcdp);
-
-       if (pcdp->rev < 3)
-               return;         /* only support PCDP (rev >= 3) */
-
-       for (bp = (u8 *)&pcdp->uart[pcdp->num_type0];
-            bp < (u8 *)pcdp + pcdp->length;
-            bp += device.length) {
-               memcpy(&device, bp, sizeof(device));
-               if (! (device.primary & PCDP_PRIMARY_CONSOLE))
-                       continue;       /* not primary console */
-
-               if (device.type != PCDP_CONSOLE_VGA)
-                       continue;       /* not VGA descriptor */
-
-               memcpy(&if_pci, bp+sizeof(device), sizeof(if_pci));
-               if (if_pci.type != PCDP_IF_PCI)
-                       continue;       /* not PCI interconnect */
-
-               if (if_pci.translation & PCDP_PCI_TRANS_IOPORT)
-                       vga_console_iobase = if_pci.ioport_tra;
-
-               if (if_pci.translation & PCDP_PCI_TRANS_MMIO)
-                       vga_console_membase =
-                               if_pci.mmio_tra | __IA64_UNCACHED_OFFSET;
-
-               break; /* once we find the primary, we're done */
-       }
-}
-#endif
-
-static unsigned long sn2_rtc_initial;
-
-/**
- * sn_setup - SN platform setup routine
- * @cmdline_p: kernel command line
- *
- * Handles platform setup for SN machines.  This includes determining
- * the RTC frequency (via a SAL call), initializing secondary CPUs, and
- * setting up per-node data areas.  The console is also initialized here.
- */
-void __init sn_setup(char **cmdline_p)
-{
-       long status, ticks_per_sec, drift;
-       u32 version = sn_sal_rev();
-       extern void sn_cpu_init(void);
-
-       sn2_rtc_initial = rtc_time();
-       ia64_sn_plat_set_error_handling_features();     // obsolete
-       ia64_sn_set_os_feature(OSF_MCA_SLV_TO_OS_INIT_SLV);
-       ia64_sn_set_os_feature(OSF_FEAT_LOG_SBES);
-       /*
-        * Note: The calls to notify the PROM of ACPI and PCI Segment
-        *       support must be done prior to acpi_load_tables(), as
-        *       an ACPI capable PROM will rebuild the DSDT as result
-        *       of the call.
-        */
-       ia64_sn_set_os_feature(OSF_PCISEGMENT_ENABLE);
-       ia64_sn_set_os_feature(OSF_ACPI_ENABLE);
-
-       /* Load the new DSDT and SSDT tables into the global table list. */
-       acpi_table_init();
-
-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
-       /*
-        * Handle SN vga console.
-        *
-        * SN systems do not have enough ACPI table information
-        * being passed from prom to identify VGA adapters and the legacy
-        * addresses to access them.  Until that is done, SN systems rely
-        * on the PCDP table to identify the primary VGA console if one
-        * exists.
-        *
-        * However, kernel PCDP support is optional, and even if it is built
-        * into the kernel, it will not be used if the boot cmdline contains
-        * console= directives.
-        *
-        * So, to work around this mess, we duplicate some of the PCDP code
-        * here so that the primary VGA console (as defined by PCDP) will
-        * work on SN systems even if a different console (e.g. serial) is
-        * selected on the boot line (or CONFIG_EFI_PCDP is off).
-        */
-
-       if (! vga_console_membase)
-               sn_scan_pcdp();
-
-       /*
-        *      Setup legacy IO space.
-        *      vga_console_iobase maps to PCI IO Space address 0 on the
-        *      bus containing the VGA console.
-        */
-       if (vga_console_iobase) {
-               io_space[0].mmio_base =
-                       (unsigned long) ioremap(vga_console_iobase, 0);
-               io_space[0].sparse = 0;
-       }
-
-       if (vga_console_membase) {
-               /* usable vga ... make tty0 the preferred default console */
-               if (!strstr(*cmdline_p, "console="))
-                       add_preferred_console("tty", 0, NULL);
-       } else {
-               printk(KERN_DEBUG "SGI: Disabling VGA console\n");
-               if (!strstr(*cmdline_p, "console="))
-                       add_preferred_console("ttySG", 0, NULL);
-#ifdef CONFIG_DUMMY_CONSOLE
-               conswitchp = &dummy_con;
-#else
-               conswitchp = NULL;
-#endif                         /* CONFIG_DUMMY_CONSOLE */
-       }
-#endif                         /* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */
-
-       MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY;
-
-       /*
-        * Build the tables for managing cnodes.
-        */
-       build_cnode_tables();
-
-       status =
-           ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec,
-                              &drift);
-       if (status != 0 || ticks_per_sec < 100000) {
-               printk(KERN_WARNING
-                      "unable to determine platform RTC clock frequency, guessing.\n");
-               /* PROM gives wrong value for clock freq. so guess */
-               sn_rtc_cycles_per_second = 1000000000000UL / 30000UL;
-       } else
-               sn_rtc_cycles_per_second = ticks_per_sec;
-
-       platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR;
-
-       printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
-
-       /*
-        * we set the default root device to /dev/hda
-        * to make simulation easy
-        */
-       ROOT_DEV = Root_HDA1;
-
-       /*
-        * Create the PDAs and NODEPDAs for all the cpus.
-        */
-       sn_init_pdas(cmdline_p);
-
-       ia64_mark_idle = &snidle;
-
-       /*
-        * For the bootcpu, we do this here. All other cpus will make the
-        * call as part of cpu_init in slave cpu initialization.
-        */
-       sn_cpu_init();
-
-#ifdef CONFIG_SMP
-       init_smp_config();
-#endif
-       screen_info = sn_screen_info;
-
-       sn_timer_init();
-
-       /*
-        * set pm_power_off to a SAL call to allow
-        * sn machines to power off. The SAL call can be replaced
-        * by an ACPI interface call when ACPI is fully implemented
-        * for sn.
-        */
-       pm_power_off = ia64_sn_power_down;
-       current->thread.flags |= IA64_THREAD_MIGRATION;
-}
-
-/**
- * sn_init_pdas - setup node data areas
- *
- * One time setup for Node Data Area.  Called by sn_setup().
- */
-static void __init sn_init_pdas(char **cmdline_p)
-{
-       cnodeid_t cnode;
-
-       /*
-        * Allocate & initialize the nodepda for each node.
-        */
-       for_each_online_node(cnode) {
-               nodepdaindr[cnode] =
-                   memblock_alloc_node(sizeof(nodepda_t), SMP_CACHE_BYTES,
-                                       cnode);
-               if (!nodepdaindr[cnode])
-                       panic("%s: Failed to allocate %lu bytes align=0x%x nid=%d\n",
-                             __func__, sizeof(nodepda_t), SMP_CACHE_BYTES,
-                             cnode);
-               memset(nodepdaindr[cnode]->phys_cpuid, -1,
-                   sizeof(nodepdaindr[cnode]->phys_cpuid));
-               spin_lock_init(&nodepdaindr[cnode]->ptc_lock);
-       }
-
-       /*
-        * Allocate & initialize nodepda for TIOs.  For now, put them on node 0.
-        */
-       for (cnode = num_online_nodes(); cnode < num_cnodes; cnode++) {
-               nodepdaindr[cnode] =
-                   memblock_alloc_node(sizeof(nodepda_t), SMP_CACHE_BYTES, 0);
-               if (!nodepdaindr[cnode])
-                       panic("%s: Failed to allocate %lu bytes align=0x%x nid=%d\n",
-                             __func__, sizeof(nodepda_t), SMP_CACHE_BYTES,
-                             cnode);
-       }
-
-
-       /*
-        * Now copy the array of nodepda pointers to each nodepda.
-        */
-       for (cnode = 0; cnode < num_cnodes; cnode++)
-               memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr,
-                      sizeof(nodepdaindr));
-
-       /*
-        * Set up IO related platform-dependent nodepda fields.
-        * The following routine actually sets up the hubinfo struct
-        * in nodepda.
-        */
-       for_each_online_node(cnode) {
-               bte_init_node(nodepdaindr[cnode], cnode);
-       }
-
-       /*
-        * Initialize the per node hubdev.  This includes IO Nodes and
-        * headless/memless nodes.
-        */
-       for (cnode = 0; cnode < num_cnodes; cnode++) {
-               hubdev_init_node(nodepdaindr[cnode], cnode);
-       }
-}
-
-/**
- * sn_cpu_init - initialize per-cpu data areas
- * @cpuid: cpuid of the caller
- *
- * Called during cpu initialization on each cpu as it starts.
- * Currently, initializes the per-cpu data area for SNIA.
- * Also sets up a few fields in the nodepda.  Also known as
- * platform_cpu_init() by the ia64 machvec code.
- */
-void sn_cpu_init(void)
-{
-       int cpuid;
-       int cpuphyid;
-       int nasid;
-       int subnode;
-       int slice;
-       int cnode;
-       int i;
-       static int wars_have_been_checked, set_cpu0_number;
-
-       cpuid = smp_processor_id();
-       if (cpuid == 0 && IS_MEDUSA()) {
-               if (ia64_sn_is_fake_prom())
-                       sn_prom_type = 2;
-               else
-                       sn_prom_type = 1;
-               printk(KERN_INFO "Running on medusa with %s PROM\n",
-                      (sn_prom_type == 1) ? "real" : "fake");
-       }
-
-       memset(pda, 0, sizeof(*pda));
-       if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2,
-                               &sn_hub_info->nasid_bitmask,
-                               &sn_hub_info->nasid_shift,
-                               &sn_system_size, &sn_sharing_domain_size,
-                               &sn_partition_id, &sn_coherency_id,
-                               &sn_region_size))
-               BUG();
-       sn_hub_info->as_shift = sn_hub_info->nasid_shift - 2;
-
-       /*
-        * Don't check status. The SAL call is not supported on all PROMs
-        * but a failure is harmless.
-        * Architecturally, cpu_init is always called twice on cpu 0. We
-        * should set cpu_number on cpu 0 once.
-        */
-       if (cpuid == 0) {
-               if (!set_cpu0_number) {
-                       (void) ia64_sn_set_cpu_number(cpuid);
-                       set_cpu0_number = 1;
-               }
-       } else
-               (void) ia64_sn_set_cpu_number(cpuid);
-
-       /*
-        * The boot cpu makes this call again after platform initialization is
-        * complete.
-        */
-       if (nodepdaindr[0] == NULL)
-               return;
-
-       for (i = 0; i < MAX_PROM_FEATURE_SETS; i++)
-               if (ia64_sn_get_prom_feature_set(i, &sn_prom_features[i]) != 0)
-                       break;
-
-       cpuphyid = get_sapicid();
-
-       if (ia64_sn_get_sapic_info(cpuphyid, &nasid, &subnode, &slice))
-               BUG();
-
-       for (i=0; i < MAX_NUMNODES; i++) {
-               if (nodepdaindr[i]) {
-                       nodepdaindr[i]->phys_cpuid[cpuid].nasid = nasid;
-                       nodepdaindr[i]->phys_cpuid[cpuid].slice = slice;
-                       nodepdaindr[i]->phys_cpuid[cpuid].subnode = subnode;
-               }
-       }
-
-       cnode = nasid_to_cnodeid(nasid);
-
-       __this_cpu_write(__sn_nodepda, nodepdaindr[cnode]);
-
-       pda->led_address =
-           (typeof(pda->led_address)) (LED0 + (slice << LED_CPU_SHIFT));
-       pda->led_state = LED_ALWAYS_SET;
-       pda->hb_count = HZ / 2;
-       pda->hb_state = 0;
-       pda->idle_flag = 0;
-
-       if (cpuid != 0) {
-               /* copy cpu 0's sn_cnodeid_to_nasid table to this cpu's */
-               memcpy(sn_cnodeid_to_nasid,
-                      (&per_cpu(__sn_cnodeid_to_nasid, 0)),
-                      sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid)));
-       }
-
-       /*
-        * Check for WARs.
-        * Only needs to be done once, on BSP.
-        * Has to be done after loop above, because it uses this cpu's
-        * sn_cnodeid_to_nasid table which was just initialized if this
-        * isn't cpu 0.
-        * Has to be done before assignment below.
-        */
-       if (!wars_have_been_checked) {
-               sn_check_for_wars();
-               wars_have_been_checked = 1;
-       }
-       sn_hub_info->shub_1_1_found = shub_1_1_found;
-
-       /*
-        * Set up addresses of PIO/MEM write status registers.
-        */
-       {
-               u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
-               u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2,
-                       SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3};
-               u64 *pio;
-               pio = is_shub1() ? pio1 : pio2;
-               pda->pio_write_status_addr =
-                  (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, pio[slice]);
-               pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0;
-       }
-
-       /*
-        * WAR addresses for SHUB 1.x.
-        */
-       if (local_node_data->active_cpu_count++ == 0 && is_shub1()) {
-               int buddy_nasid;
-               buddy_nasid =
-                   cnodeid_to_nasid(numa_node_id() ==
-                                    num_online_nodes() - 1 ? 0 : numa_node_id() + 1);
-               pda->pio_shub_war_cam_addr =
-                   (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid,
-                                                             SH1_PI_CAM_CONTROL);
-       }
-}
-
-/*
- * Build tables for converting between NASIDs and cnodes.
- */
-static inline int __init board_needs_cnode(int type)
-{
-       return (type == KLTYPE_SNIA || type == KLTYPE_TIO);
-}
-
-void __init build_cnode_tables(void)
-{
-       int nasid;
-       int node;
-       lboard_t *brd;
-
-       memset(physical_node_map, -1, sizeof(physical_node_map));
-       memset(sn_cnodeid_to_nasid, -1,
-                       sizeof(__ia64_per_cpu_var(__sn_cnodeid_to_nasid)));
-
-       /*
-        * First populate the tables with C/M bricks. This ensures that
-        * cnode == node for all C & M bricks.
-        */
-       for_each_online_node(node) {
-               nasid = pxm_to_nasid(node_to_pxm(node));
-               sn_cnodeid_to_nasid[node] = nasid;
-               physical_node_map[nasid] = node;
-       }
-
-       /*
-        * num_cnodes is total number of C/M/TIO bricks. Because of the 256 node
-        * limit on the number of nodes, we can't use the generic node numbers 
-        * for this. Note that num_cnodes is incremented below as TIOs or
-        * headless/memoryless nodes are discovered.
-        */
-       num_cnodes = num_online_nodes();
-
-       /* fakeprom does not support klgraph */
-       if (IS_RUNNING_ON_FAKE_PROM())
-               return;
-
-       /* Find TIOs & headless/memoryless nodes and add them to the tables */
-       for_each_online_node(node) {
-               kl_config_hdr_t *klgraph_header;
-               nasid = cnodeid_to_nasid(node);
-               klgraph_header = ia64_sn_get_klconfig_addr(nasid);
-               BUG_ON(klgraph_header == NULL);
-               brd = NODE_OFFSET_TO_LBOARD(nasid, klgraph_header->ch_board_info);
-               while (brd) {
-                       if (board_needs_cnode(brd->brd_type) && physical_node_map[brd->brd_nasid] < 0) {
-                               sn_cnodeid_to_nasid[num_cnodes] = brd->brd_nasid;
-                               physical_node_map[brd->brd_nasid] = num_cnodes++;
-                       }
-                       brd = find_lboard_next(brd);
-               }
-       }
-}
-
-int
-nasid_slice_to_cpuid(int nasid, int slice)
-{
-       long cpu;
-
-       for (cpu = 0; cpu < nr_cpu_ids; cpu++)
-               if (cpuid_to_nasid(cpu) == nasid &&
-                                       cpuid_to_slice(cpu) == slice)
-                       return cpu;
-
-       return -1;
-}
-
-int sn_prom_feature_available(int id)
-{
-       if (id >= BITS_PER_LONG * MAX_PROM_FEATURE_SETS)
-               return 0;
-       return test_bit(id, sn_prom_features);
-}
-
-void
-sn_kernel_launch_event(void)
-{
-       /* ignore status until we understand possible failure, if any*/
-       if (ia64_sn_kernel_launch_event())
-               printk(KERN_ERR "KEXEC is not supported in this PROM, Please update the PROM.\n");
-}
-EXPORT_SYMBOL(sn_prom_feature_available);
-
diff --git a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile
deleted file mode 100644 (file)
index 170bde4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# arch/ia64/sn/kernel/sn2/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
-#
-# sn2 specific kernel files
-#
-
-obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \
-        prominfo_proc.o timer.o timer_interrupt.o sn_hwperf.o
diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c
deleted file mode 100644 (file)
index 2862cb3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- * 
- * Copyright (C) 2001-2003, 2006 Silicon Graphics, Inc. All rights reserved.
- *
- */
-#include <linux/module.h>
-#include <asm/pgalloc.h>
-#include <asm/sn/arch.h>
-
-/**
- * sn_flush_all_caches - flush a range of address from all caches (incl. L4)
- * @flush_addr: identity mapped region 7 address to start flushing
- * @bytes: number of bytes to flush
- *
- * Flush a range of addresses from all caches including L4. 
- * All addresses fully or partially contained within 
- * @flush_addr to @flush_addr + @bytes are flushed
- * from all caches.
- */
-void
-sn_flush_all_caches(long flush_addr, long bytes)
-{
-       unsigned long addr = flush_addr;
-
-       /* SHub1 requires a cached address */
-       if (is_shub1() && (addr & RGN_BITS) == RGN_BASE(RGN_UNCACHED))
-               addr = (addr - RGN_BASE(RGN_UNCACHED)) + RGN_BASE(RGN_KERNEL);
-
-       flush_icache_range(addr, addr + bytes);
-       /*
-        * The last call may have returned before the caches
-        * were actually flushed, so we call it again to make
-        * sure.
-        */
-       flush_icache_range(addr, addr + bytes);
-       mb();
-}
-EXPORT_SYMBOL(sn_flush_all_caches);
diff --git a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c
deleted file mode 100644 (file)
index a12c058..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* 
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved.
- *
- * The generic kernel requires function pointers to these routines, so
- * we wrap the inlines from asm/ia64/sn/sn2/io.h here.
- */
-
-#include <asm/sn/io.h>
-
-#ifdef CONFIG_IA64_GENERIC
-
-#undef __sn_inb
-#undef __sn_inw
-#undef __sn_inl
-#undef __sn_outb
-#undef __sn_outw
-#undef __sn_outl
-#undef __sn_readb
-#undef __sn_readw
-#undef __sn_readl
-#undef __sn_readq
-#undef __sn_readb_relaxed
-#undef __sn_readw_relaxed
-#undef __sn_readl_relaxed
-#undef __sn_readq_relaxed
-
-unsigned int __sn_inb(unsigned long port)
-{
-       return ___sn_inb(port);
-}
-
-unsigned int __sn_inw(unsigned long port)
-{
-       return ___sn_inw(port);
-}
-
-unsigned int __sn_inl(unsigned long port)
-{
-       return ___sn_inl(port);
-}
-
-void __sn_outb(unsigned char val, unsigned long port)
-{
-       ___sn_outb(val, port);
-}
-
-void __sn_outw(unsigned short val, unsigned long port)
-{
-       ___sn_outw(val, port);
-}
-
-void __sn_outl(unsigned int val, unsigned long port)
-{
-       ___sn_outl(val, port);
-}
-
-unsigned char __sn_readb(void __iomem *addr)
-{
-       return ___sn_readb(addr);
-}
-
-unsigned short __sn_readw(void __iomem *addr)
-{
-       return ___sn_readw(addr);
-}
-
-unsigned int __sn_readl(void __iomem *addr)
-{
-       return ___sn_readl(addr);
-}
-
-unsigned long __sn_readq(void __iomem *addr)
-{
-       return ___sn_readq(addr);
-}
-
-unsigned char __sn_readb_relaxed(void __iomem *addr)
-{
-       return ___sn_readb_relaxed(addr);
-}
-
-unsigned short __sn_readw_relaxed(void __iomem *addr)
-{
-       return ___sn_readw_relaxed(addr);
-}
-
-unsigned int __sn_readl_relaxed(void __iomem *addr)
-{
-       return ___sn_readl_relaxed(addr);
-}
-
-unsigned long __sn_readq_relaxed(void __iomem *addr)
-{
-       return ___sn_readq_relaxed(addr);
-}
-
-#endif
diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c
deleted file mode 100644 (file)
index e15457b..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999,2001-2004, 2006 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * Module to export the system's Firmware Interface Tables, including
- * PROM revision numbers and banners, in /proc
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/nodemask.h>
-#include <asm/io.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/addrs.h>
-
-MODULE_DESCRIPTION("PROM version reporting for /proc");
-MODULE_AUTHOR("Chad Talbott");
-MODULE_LICENSE("GPL");
-
-/* Standard Intel FIT entry types */
-#define FIT_ENTRY_FIT_HEADER   0x00    /* FIT header entry */
-#define FIT_ENTRY_PAL_B                0x01    /* PAL_B entry */
-/* Entries 0x02 through 0x0D reserved by Intel */
-#define FIT_ENTRY_PAL_A_PROC   0x0E    /* Processor-specific PAL_A entry */
-#define FIT_ENTRY_PAL_A                0x0F    /* PAL_A entry, same as... */
-#define FIT_ENTRY_PAL_A_GEN    0x0F    /* ...Generic PAL_A entry */
-#define FIT_ENTRY_UNUSED       0x7F    /* Unused (reserved by Intel?) */
-/* OEM-defined entries range from 0x10 to 0x7E. */
-#define FIT_ENTRY_SAL_A                0x10    /* SAL_A entry */
-#define FIT_ENTRY_SAL_B                0x11    /* SAL_B entry */
-#define FIT_ENTRY_SALRUNTIME   0x12    /* SAL runtime entry */
-#define FIT_ENTRY_EFI          0x1F    /* EFI entry */
-#define FIT_ENTRY_FPSWA                0x20    /* embedded fpswa entry */
-#define FIT_ENTRY_VMLINUX      0x21    /* embedded vmlinux entry */
-
-#define FIT_MAJOR_SHIFT        (32 + 8)
-#define FIT_MAJOR_MASK ((1 << 8) - 1)
-#define FIT_MINOR_SHIFT        32
-#define FIT_MINOR_MASK ((1 << 8) - 1)
-
-#define FIT_MAJOR(q)   \
-       ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK)
-#define FIT_MINOR(q)   \
-       ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK)
-
-#define FIT_TYPE_SHIFT (32 + 16)
-#define FIT_TYPE_MASK  ((1 << 7) - 1)
-
-#define FIT_TYPE(q)    \
-       ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK)
-
-struct fit_type_map_t {
-       unsigned char type;
-       const char *name;
-};
-
-static const struct fit_type_map_t fit_entry_types[] = {
-       {FIT_ENTRY_FIT_HEADER, "FIT Header"},
-       {FIT_ENTRY_PAL_A_GEN, "Generic PAL_A"},
-       {FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A"},
-       {FIT_ENTRY_PAL_A, "PAL_A"},
-       {FIT_ENTRY_PAL_B, "PAL_B"},
-       {FIT_ENTRY_SAL_A, "SAL_A"},
-       {FIT_ENTRY_SAL_B, "SAL_B"},
-       {FIT_ENTRY_SALRUNTIME, "SAL runtime"},
-       {FIT_ENTRY_EFI, "EFI"},
-       {FIT_ENTRY_VMLINUX, "Embedded Linux"},
-       {FIT_ENTRY_FPSWA, "Embedded FPSWA"},
-       {FIT_ENTRY_UNUSED, "Unused"},
-       {0xff, "Error"},
-};
-
-static const char *fit_type_name(unsigned char type)
-{
-       struct fit_type_map_t const *mapp;
-
-       for (mapp = fit_entry_types; mapp->type != 0xff; mapp++)
-               if (type == mapp->type)
-                       return mapp->name;
-
-       if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED))
-               return "OEM type";
-       if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A))
-               return "Reserved";
-
-       return "Unknown type";
-}
-
-static int
-get_fit_entry(unsigned long nasid, int index, unsigned long *fentry,
-             char *banner, int banlen)
-{
-       return ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen);
-}
-
-
-/*
- * These two routines display the FIT table for each node.
- */
-static void dump_fit_entry(struct seq_file *m, unsigned long *fentry)
-{
-       unsigned type;
-
-       type = FIT_TYPE(fentry[1]);
-       seq_printf(m, "%02x %-25s %x.%02x %016lx %u\n",
-                  type,
-                  fit_type_name(type),
-                  FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]),
-                  fentry[0],
-                  /* mult by sixteen to get size in bytes */
-                  (unsigned)(fentry[1] & 0xffffff) * 16);
-}
-
-
-/*
- * We assume that the fit table will be small enough that we can print
- * the whole thing into one page.  (This is true for our default 16kB
- * pages -- each entry is about 60 chars wide when printed.)  I read
- * somewhere that the maximum size of the FIT is 128 entries, so we're
- * OK except for 4kB pages (and no one is going to do that on SN
- * anyway).
- */
-static int proc_fit_show(struct seq_file *m, void *v)
-{
-       unsigned long nasid = (unsigned long)m->private;
-       unsigned long fentry[2];
-       int index;
-
-       for (index=0;;index++) {
-               BUG_ON(index * 60 > PAGE_SIZE);
-               if (get_fit_entry(nasid, index, fentry, NULL, 0))
-                       break;
-               dump_fit_entry(m, fentry);
-       }
-       return 0;
-}
-
-static int proc_version_show(struct seq_file *m, void *v)
-{
-       unsigned long nasid = (unsigned long)m->private;
-       unsigned long fentry[2];
-       char banner[128];
-       int index;
-
-       for (index = 0; ; index++) {
-               if (get_fit_entry(nasid, index, fentry, banner,
-                                 sizeof(banner)))
-                       return 0;
-               if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A)
-                       break;
-       }
-
-       seq_printf(m, "%x.%02x\n", FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]));
-
-       if (banner[0])
-               seq_printf(m, "%s\n", banner);
-       return 0;
-}
-
-/* module entry points */
-int __init prominfo_init(void);
-void __exit prominfo_exit(void);
-
-module_init(prominfo_init);
-module_exit(prominfo_exit);
-
-#define NODE_NAME_LEN 11
-
-int __init prominfo_init(void)
-{
-       struct proc_dir_entry *sgi_prominfo_entry;
-       cnodeid_t cnodeid;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL);
-       if (!sgi_prominfo_entry)
-               return -ENOMEM;
-
-       for_each_online_node(cnodeid) {
-               struct proc_dir_entry *dir;
-               unsigned long nasid;
-               char name[NODE_NAME_LEN];
-
-               sprintf(name, "node%d", cnodeid);
-               dir = proc_mkdir(name, sgi_prominfo_entry);
-               if (!dir)
-                       continue;
-               nasid = cnodeid_to_nasid(cnodeid);
-               proc_create_single_data("fit", 0, dir, proc_fit_show, 
-                               (void *)nasid);
-               proc_create_single_data("version", 0, dir, proc_version_show,
-                               (void *)nasid);
-       }
-       return 0;
-}
-
-void __exit prominfo_exit(void)
-{
-       remove_proc_subtree("sgi_prominfo", NULL);
-}
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
deleted file mode 100644 (file)
index bebbcc4..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* 
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <asm/types.h>
-#include <asm/sn/shub_mmr.h>
-
-#define DEADLOCKBIT    SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
-#define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK
-#define ALIAS_OFFSET   8
-
-
-       .global sn2_ptc_deadlock_recovery_core
-       .proc   sn2_ptc_deadlock_recovery_core
-
-sn2_ptc_deadlock_recovery_core:
-       .regstk 6,0,0,0
-
-       ptc0     = in0
-       data0    = in1
-       ptc1     = in2
-       data1    = in3
-       piowc    = in4
-       zeroval  = in5
-       piowcphy = r30
-       psrsave  = r2
-       scr1     = r16
-       scr2     = r17
-       mask     = r18
-
-
-       extr.u  piowcphy=piowc,0,61;;   // Convert piowc to uncached physical address
-       dep     piowcphy=-1,piowcphy,63,1
-       movl    mask=WRITECOUNTMASK
-       mov     r8=r0
-
-1:
-       cmp.ne  p8,p9=r0,ptc1           // Test for shub type (ptc1 non-null on shub1)
-                                       // p8 = 1 if shub1, p9 = 1 if shub2
-
-       add     scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register 
-       mov     scr1=7;;                // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
-(p8)   st8.rel [scr2]=scr1;;
-(p9)   ld8.acq scr1=[scr2];;
-
-5:     ld8.acq scr1=[piowc];;          // Wait for PIOs to complete.
-       hint    @pause
-       and     scr2=scr1,mask;;        // mask of writecount bits
-       cmp.ne  p6,p0=zeroval,scr2
-(p6)   br.cond.sptk 5b
-       
-
-
-       ////////////// BEGIN PHYSICAL MODE ////////////////////
-       mov psrsave=psr                 // Disable IC (no PMIs)
-       rsm psr.i | psr.dt | psr.ic;;
-       srlz.i;;
-
-       st8.rel [ptc0]=data0            // Write PTC0 & wait for completion.
-
-5:     ld8.acq scr1=[piowcphy];;       // Wait for PIOs to complete.
-       hint    @pause
-       and     scr2=scr1,mask;;        // mask of writecount bits
-       cmp.ne  p6,p0=zeroval,scr2
-(p6)   br.cond.sptk 5b;;
-
-       tbit.nz p8,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK
-(p7)   cmp.ne p7,p0=r0,ptc1;;          // Test for non-null ptc1
-       
-(p7)   st8.rel [ptc1]=data1;;          // Now write PTC1.
-
-5:     ld8.acq scr1=[piowcphy];;       // Wait for PIOs to complete.
-       hint    @pause
-       and     scr2=scr1,mask;;        // mask of writecount bits
-       cmp.ne  p6,p0=zeroval,scr2
-(p6)   br.cond.sptk 5b
-       
-       tbit.nz p8,p0=scr1,DEADLOCKBIT;;// Test for DEADLOCK
-
-       mov psr.l=psrsave;;             // Reenable IC
-       srlz.i;;
-       ////////////// END   PHYSICAL MODE ////////////////////
-
-(p8)   add     r8=1,r8
-(p8)   br.cond.spnt 1b;;               // Repeat if DEADLOCK occurred.
-
-       br.ret.sptk     rp
-       .endp sn2_ptc_deadlock_recovery_core
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
deleted file mode 100644 (file)
index b510f4f..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * SN2 Platform specific SMP Support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/mm_types.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/mmzone.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/nodemask.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/sal.h>
-#include <asm/delay.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/tlb.h>
-#include <asm/numa.h>
-#include <asm/hw_irq.h>
-#include <asm/current.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/rw_mmr.h>
-#include <asm/sn/sn_feature_sets.h>
-
-DEFINE_PER_CPU(struct ptc_stats, ptcstats);
-DECLARE_PER_CPU(struct ptc_stats, ptcstats);
-
-static  __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
-
-/* 0 = old algorithm (no IPI flushes), 1 = ipi deadlock flush, 2 = ipi instead of SHUB ptc, >2 = always ipi */
-static int sn2_flush_opt = 0;
-
-extern unsigned long
-sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
-                              volatile unsigned long *, unsigned long,
-                              volatile unsigned long *, unsigned long);
-void
-sn2_ptc_deadlock_recovery(nodemask_t, short, short, int,
-                         volatile unsigned long *, unsigned long,
-                         volatile unsigned long *, unsigned long);
-
-/*
- * Note: some is the following is captured here to make degugging easier
- * (the macros make more sense if you see the debug patch - not posted)
- */
-#define sn2_ptctest    0
-#define local_node_uses_ptc_ga(sh1)    ((sh1) ? 1 : 0)
-#define max_active_pio(sh1)            ((sh1) ? 32 : 7)
-#define reset_max_active_on_deadlock() 1
-#define PTC_LOCK(sh1)                  ((sh1) ? &sn2_global_ptc_lock : &sn_nodepda->ptc_lock)
-
-struct ptc_stats {
-       unsigned long ptc_l;
-       unsigned long change_rid;
-       unsigned long shub_ptc_flushes;
-       unsigned long nodes_flushed;
-       unsigned long deadlocks;
-       unsigned long deadlocks2;
-       unsigned long lock_itc_clocks;
-       unsigned long shub_itc_clocks;
-       unsigned long shub_itc_clocks_max;
-       unsigned long shub_ptc_flushes_not_my_mm;
-       unsigned long shub_ipi_flushes;
-       unsigned long shub_ipi_flushes_itc_clocks;
-};
-
-#define sn2_ptctest    0
-
-static inline unsigned long wait_piowc(void)
-{
-       volatile unsigned long *piows;
-       unsigned long zeroval, ws;
-
-       piows = pda->pio_write_status_addr;
-       zeroval = pda->pio_write_status_val;
-       do {
-               cpu_relax();
-       } while (((ws = *piows) & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != zeroval);
-       return (ws & SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK) != 0;
-}
-
-/**
- * sn_migrate - SN-specific task migration actions
- * @task: Task being migrated to new CPU
- *
- * SN2 PIO writes from separate CPUs are not guaranteed to arrive in order.
- * Context switching user threads which have memory-mapped MMIO may cause
- * PIOs to issue from separate CPUs, thus the PIO writes must be drained
- * from the previous CPU's Shub before execution resumes on the new CPU.
- */
-void sn_migrate(struct task_struct *task)
-{
-       pda_t *last_pda = pdacpu(task_thread_info(task)->last_cpu);
-       volatile unsigned long *adr = last_pda->pio_write_status_addr;
-       unsigned long val = last_pda->pio_write_status_val;
-
-       /* Drain PIO writes from old CPU's Shub */
-       while (unlikely((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK)
-                       != val))
-               cpu_relax();
-}
-
-static void
-sn2_ipi_flush_all_tlb(struct mm_struct *mm)
-{
-       unsigned long itc;
-
-       itc = ia64_get_itc();
-       smp_flush_tlb_cpumask(*mm_cpumask(mm));
-       itc = ia64_get_itc() - itc;
-       __this_cpu_add(ptcstats.shub_ipi_flushes_itc_clocks, itc);
-       __this_cpu_inc(ptcstats.shub_ipi_flushes);
-}
-
-/**
- * sn2_global_tlb_purge - globally purge translation cache of virtual address range
- * @mm: mm_struct containing virtual address range
- * @start: start of virtual address range
- * @end: end of virtual address range
- * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc))
- *
- * Purges the translation caches of all processors of the given virtual address
- * range.
- *
- * Note:
- *     - cpu_vm_mask is a bit mask that indicates which cpus have loaded the context.
- *     - cpu_vm_mask is converted into a nodemask of the nodes containing the
- *       cpus in cpu_vm_mask.
- *     - if only one bit is set in cpu_vm_mask & it is the current cpu & the
- *       process is purging its own virtual address range, then only the
- *       local TLB needs to be flushed. This flushing can be done using
- *       ptc.l. This is the common case & avoids the global spinlock.
- *     - if multiple cpus have loaded the context, then flushing has to be
- *       done with ptc.g/MMRs under protection of the global ptc_lock.
- */
-
-void
-sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
-                    unsigned long end, unsigned long nbits)
-{
-       int i, ibegin, shub1, cnode, mynasid, cpu, lcpu = 0, nasid;
-       int mymm = (mm == current->active_mm && mm == current->mm);
-       int use_cpu_ptcga;
-       volatile unsigned long *ptc0, *ptc1;
-       unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0;
-       short nix;
-       nodemask_t nodes_flushed;
-       int active, max_active, deadlock, flush_opt = sn2_flush_opt;
-
-       if (flush_opt > 2) {
-               sn2_ipi_flush_all_tlb(mm);
-               return;
-       }
-
-       nodes_clear(nodes_flushed);
-       i = 0;
-
-       for_each_cpu(cpu, mm_cpumask(mm)) {
-               cnode = cpu_to_node(cpu);
-               node_set(cnode, nodes_flushed);
-               lcpu = cpu;
-               i++;
-       }
-
-       if (i == 0)
-               return;
-
-       preempt_disable();
-
-       if (likely(i == 1 && lcpu == smp_processor_id() && mymm)) {
-               do {
-                       ia64_ptcl(start, nbits << 2);
-                       start += (1UL << nbits);
-               } while (start < end);
-               ia64_srlz_i();
-               __this_cpu_inc(ptcstats.ptc_l);
-               preempt_enable();
-               return;
-       }
-
-       if (atomic_read(&mm->mm_users) == 1 && mymm) {
-               flush_tlb_mm(mm);
-               __this_cpu_inc(ptcstats.change_rid);
-               preempt_enable();
-               return;
-       }
-
-       if (flush_opt == 2) {
-               sn2_ipi_flush_all_tlb(mm);
-               preempt_enable();
-               return;
-       }
-
-       itc = ia64_get_itc();
-       nix = nodes_weight(nodes_flushed);
-
-       rr_value = (mm->context << 3) | REGION_NUMBER(start);
-
-       shub1 = is_shub1();
-       if (shub1) {
-               data0 = (1UL << SH1_PTC_0_A_SHFT) |
-                       (nbits << SH1_PTC_0_PS_SHFT) |
-                       (rr_value << SH1_PTC_0_RID_SHFT) |
-                       (1UL << SH1_PTC_0_START_SHFT);
-               ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_0);
-               ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_1);
-       } else {
-               data0 = (1UL << SH2_PTC_A_SHFT) |
-                       (nbits << SH2_PTC_PS_SHFT) |
-                       (1UL << SH2_PTC_START_SHFT);
-               ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH2_PTC + 
-                       (rr_value << SH2_PTC_RID_SHFT));
-               ptc1 = NULL;
-       }
-       
-
-       mynasid = get_nasid();
-       use_cpu_ptcga = local_node_uses_ptc_ga(shub1);
-       max_active = max_active_pio(shub1);
-
-       itc = ia64_get_itc();
-       spin_lock_irqsave(PTC_LOCK(shub1), flags);
-       itc2 = ia64_get_itc();
-
-       __this_cpu_add(ptcstats.lock_itc_clocks, itc2 - itc);
-       __this_cpu_inc(ptcstats.shub_ptc_flushes);
-       __this_cpu_add(ptcstats.nodes_flushed, nix);
-       if (!mymm)
-                __this_cpu_inc(ptcstats.shub_ptc_flushes_not_my_mm);
-
-       if (use_cpu_ptcga && !mymm) {
-               old_rr = ia64_get_rr(start);
-               ia64_set_rr(start, (old_rr & 0xff) | (rr_value << 8));
-               ia64_srlz_d();
-       }
-
-       wait_piowc();
-       do {
-               if (shub1)
-                       data1 = start | (1UL << SH1_PTC_1_START_SHFT);
-               else
-                       data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK);
-               deadlock = 0;
-               active = 0;
-               ibegin = 0;
-               i = 0;
-               for_each_node_mask(cnode, nodes_flushed) {
-                       nasid = cnodeid_to_nasid(cnode);
-                       if (use_cpu_ptcga && unlikely(nasid == mynasid)) {
-                               ia64_ptcga(start, nbits << 2);
-                               ia64_srlz_i();
-                       } else {
-                               ptc0 = CHANGE_NASID(nasid, ptc0);
-                               if (ptc1)
-                                       ptc1 = CHANGE_NASID(nasid, ptc1);
-                               pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1);
-                               active++;
-                       }
-                       if (active >= max_active || i == (nix - 1)) {
-                               if ((deadlock = wait_piowc())) {
-                                       if (flush_opt == 1)
-                                               goto done;
-                                       sn2_ptc_deadlock_recovery(nodes_flushed, ibegin, i, mynasid, ptc0, data0, ptc1, data1);
-                                       if (reset_max_active_on_deadlock())
-                                               max_active = 1;
-                               }
-                               active = 0;
-                               ibegin = i + 1;
-                       }
-                       i++;
-               }
-               start += (1UL << nbits);
-       } while (start < end);
-
-done:
-       itc2 = ia64_get_itc() - itc2;
-       __this_cpu_add(ptcstats.shub_itc_clocks, itc2);
-       if (itc2 > __this_cpu_read(ptcstats.shub_itc_clocks_max))
-               __this_cpu_write(ptcstats.shub_itc_clocks_max, itc2);
-
-       if (old_rr) {
-               ia64_set_rr(start, old_rr);
-               ia64_srlz_d();
-       }
-
-       spin_unlock_irqrestore(PTC_LOCK(shub1), flags);
-
-       if (flush_opt == 1 && deadlock) {
-               __this_cpu_inc(ptcstats.deadlocks);
-               sn2_ipi_flush_all_tlb(mm);
-       }
-
-       preempt_enable();
-}
-
-/*
- * sn2_ptc_deadlock_recovery
- *
- * Recover from PTC deadlocks conditions. Recovery requires stepping thru each 
- * TLB flush transaction.  The recovery sequence is somewhat tricky & is
- * coded in assembly language.
- */
-
-void
-sn2_ptc_deadlock_recovery(nodemask_t nodes, short ib, short ie, int mynasid,
-                         volatile unsigned long *ptc0, unsigned long data0,
-                         volatile unsigned long *ptc1, unsigned long data1)
-{
-       short nasid, i;
-       int cnode;
-       unsigned long *piows, zeroval, n;
-
-       __this_cpu_inc(ptcstats.deadlocks);
-
-       piows = (unsigned long *) pda->pio_write_status_addr;
-       zeroval = pda->pio_write_status_val;
-
-       i = 0;
-       for_each_node_mask(cnode, nodes) {
-               if (i < ib)
-                       goto next;
-
-               if (i > ie)
-                       break;
-
-               nasid = cnodeid_to_nasid(cnode);
-               if (local_node_uses_ptc_ga(is_shub1()) && nasid == mynasid)
-                       goto next;
-
-               ptc0 = CHANGE_NASID(nasid, ptc0);
-               if (ptc1)
-                       ptc1 = CHANGE_NASID(nasid, ptc1);
-
-               n = sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval);
-               __this_cpu_add(ptcstats.deadlocks2, n);
-next:
-               i++;
-       }
-
-}
-
-/**
- * sn_send_IPI_phys - send an IPI to a Nasid and slice
- * @nasid: nasid to receive the interrupt (may be outside partition)
- * @physid: physical cpuid to receive the interrupt.
- * @vector: command to send
- * @delivery_mode: delivery mechanism
- *
- * Sends an IPI (interprocessor interrupt) to the processor specified by
- * @physid
- *
- * @delivery_mode can be one of the following
- *
- * %IA64_IPI_DM_INT - pend an interrupt
- * %IA64_IPI_DM_PMI - pend a PMI
- * %IA64_IPI_DM_NMI - pend an NMI
- * %IA64_IPI_DM_INIT - pend an INIT interrupt
- */
-void sn_send_IPI_phys(int nasid, long physid, int vector, int delivery_mode)
-{
-       long val;
-       unsigned long flags = 0;
-       volatile long *p;
-
-       p = (long *)GLOBAL_MMR_PHYS_ADDR(nasid, SH_IPI_INT);
-       val = (1UL << SH_IPI_INT_SEND_SHFT) |
-           (physid << SH_IPI_INT_PID_SHFT) |
-           ((long)delivery_mode << SH_IPI_INT_TYPE_SHFT) |
-           ((long)vector << SH_IPI_INT_IDX_SHFT) |
-           (0x000feeUL << SH_IPI_INT_BASE_SHFT);
-
-       mb();
-       if (enable_shub_wars_1_1()) {
-               spin_lock_irqsave(&sn2_global_ptc_lock, flags);
-       }
-       pio_phys_write_mmr(p, val);
-       if (enable_shub_wars_1_1()) {
-               wait_piowc();
-               spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
-       }
-
-}
-
-EXPORT_SYMBOL(sn_send_IPI_phys);
-
-/**
- * sn2_send_IPI - send an IPI to a processor
- * @cpuid: target of the IPI
- * @vector: command to send
- * @delivery_mode: delivery mechanism
- * @redirect: redirect the IPI?
- *
- * Sends an IPI (InterProcessor Interrupt) to the processor specified by
- * @cpuid.  @vector specifies the command to send, while @delivery_mode can 
- * be one of the following
- *
- * %IA64_IPI_DM_INT - pend an interrupt
- * %IA64_IPI_DM_PMI - pend a PMI
- * %IA64_IPI_DM_NMI - pend an NMI
- * %IA64_IPI_DM_INIT - pend an INIT interrupt
- */
-void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect)
-{
-       long physid;
-       int nasid;
-
-       physid = cpu_physical_id(cpuid);
-       nasid = cpuid_to_nasid(cpuid);
-
-       /* the following is used only when starting cpus at boot time */
-       if (unlikely(nasid == -1))
-               ia64_sn_get_sapic_info(physid, &nasid, NULL, NULL);
-
-       sn_send_IPI_phys(nasid, physid, vector, delivery_mode);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-/**
- * sn_cpu_disable_allowed - Determine if a CPU can be disabled.
- * @cpu - CPU that is requested to be disabled.
- *
- * CPU disable is only allowed on SHub2 systems running with a PROM
- * that supports CPU disable. It is not permitted to disable the boot processor.
- */
-bool sn_cpu_disable_allowed(int cpu)
-{
-       if (is_shub2() && sn_prom_feature_available(PRF_CPU_DISABLE_SUPPORT)) {
-               if (cpu != 0)
-                       return true;
-               else
-                       printk(KERN_WARNING
-                             "Disabling the boot processor is not allowed.\n");
-
-       } else
-               printk(KERN_WARNING
-                      "CPU disable is not supported on this system.\n");
-
-       return false;
-}
-#endif /* CONFIG_HOTPLUG_CPU */
-
-#ifdef CONFIG_PROC_FS
-
-#define PTC_BASENAME   "sgi_sn/ptc_statistics"
-
-static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
-{
-       if (*offset < nr_cpu_ids)
-               return offset;
-       return NULL;
-}
-
-static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
-{
-       (*offset)++;
-       if (*offset < nr_cpu_ids)
-               return offset;
-       return NULL;
-}
-
-static void sn2_ptc_seq_stop(struct seq_file *file, void *data)
-{
-}
-
-static int sn2_ptc_seq_show(struct seq_file *file, void *data)
-{
-       struct ptc_stats *stat;
-       int cpu;
-
-       cpu = *(loff_t *) data;
-
-       if (!cpu) {
-               seq_printf(file,
-                          "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2 ipi_fluches ipi_nsec\n");
-               seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
-       }
-
-       if (cpu < nr_cpu_ids && cpu_online(cpu)) {
-               stat = &per_cpu(ptcstats, cpu);
-               seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
-                               stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
-                               stat->deadlocks,
-                               1000 * stat->lock_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
-                               1000 * stat->shub_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
-                               1000 * stat->shub_itc_clocks_max / per_cpu(ia64_cpu_info, cpu).cyc_per_usec,
-                               stat->shub_ptc_flushes_not_my_mm,
-                               stat->deadlocks2,
-                               stat->shub_ipi_flushes,
-                               1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(ia64_cpu_info, cpu).cyc_per_usec);
-       }
-       return 0;
-}
-
-static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, size_t count, loff_t *data)
-{
-       int cpu;
-       char optstr[64];
-
-       if (count == 0 || count > sizeof(optstr))
-               return -EINVAL;
-       if (copy_from_user(optstr, user, count))
-               return -EFAULT;
-       optstr[count - 1] = '\0';
-       sn2_flush_opt = simple_strtoul(optstr, NULL, 0);
-
-       for_each_online_cpu(cpu)
-               memset(&per_cpu(ptcstats, cpu), 0, sizeof(struct ptc_stats));
-
-       return count;
-}
-
-static const struct seq_operations sn2_ptc_seq_ops = {
-       .start = sn2_ptc_seq_start,
-       .next = sn2_ptc_seq_next,
-       .stop = sn2_ptc_seq_stop,
-       .show = sn2_ptc_seq_show
-};
-
-static int sn2_ptc_proc_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &sn2_ptc_seq_ops);
-}
-
-static const struct file_operations proc_sn2_ptc_operations = {
-       .open = sn2_ptc_proc_open,
-       .read = seq_read,
-       .write = sn2_ptc_proc_write,
-       .llseek = seq_lseek,
-       .release = seq_release,
-};
-
-static struct proc_dir_entry *proc_sn2_ptc;
-
-static int __init sn2_ptc_init(void)
-{
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       proc_sn2_ptc = proc_create(PTC_BASENAME, 0444,
-                                  NULL, &proc_sn2_ptc_operations);
-       if (!proc_sn2_ptc) {
-               printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
-               return -EINVAL;
-       }
-       spin_lock_init(&sn2_global_ptc_lock);
-       return 0;
-}
-
-static void __exit sn2_ptc_exit(void)
-{
-       remove_proc_entry(PTC_BASENAME, NULL);
-}
-
-module_init(sn2_ptc_init);
-module_exit(sn2_ptc_exit);
-#endif /* CONFIG_PROC_FS */
-
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
deleted file mode 100644 (file)
index 55febd6..0000000
+++ /dev/null
@@ -1,1004 +0,0 @@
-/* 
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
- *
- * SGI Altix topology and hardware performance monitoring API.
- * Mark Goodwin <markgw@sgi.com>. 
- *
- * Creates /proc/sgi_sn/sn_topology (read-only) to export
- * info about Altix nodes, routers, CPUs and NumaLink
- * interconnection/topology.
- *
- * Also creates a dynamic misc device named "sn_hwperf"
- * that supports an ioctl interface to call down into SAL
- * to discover hw objects, topology and to read/write
- * memory mapped registers, e.g. for performance monitoring.
- * The "sn_hwperf" device is registered only after the procfs
- * file is first opened, i.e. only if/when it's needed. 
- *
- * This API is used by SGI Performance Co-Pilot and other
- * tools, see http://oss.sgi.com/projects/pcp
- */
-
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/vmalloc.h>
-#include <linux/seq_file.h>
-#include <linux/miscdevice.h>
-#include <linux/utsname.h>
-#include <linux/cpumask.h>
-#include <linux/nodemask.h>
-#include <linux/smp.h>
-#include <linux/mutex.h>
-
-#include <asm/processor.h>
-#include <asm/topology.h>
-#include <linux/uaccess.h>
-#include <asm/sal.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/module.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/sn2/sn_hwperf.h>
-#include <asm/sn/addrs.h>
-
-static void *sn_hwperf_salheap = NULL;
-static int sn_hwperf_obj_cnt = 0;
-static nasid_t sn_hwperf_master_nasid = INVALID_NASID;
-static int sn_hwperf_init(void);
-static DEFINE_MUTEX(sn_hwperf_init_mutex);
-
-#define cnode_possible(n)      ((n) < num_cnodes)
-
-static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret)
-{
-       int e;
-       u64 sz;
-       struct sn_hwperf_object_info *objbuf = NULL;
-
-       if ((e = sn_hwperf_init()) < 0) {
-               printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e);
-               goto out;
-       }
-
-       sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info);
-       objbuf = vmalloc(sz);
-       if (objbuf == NULL) {
-               printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz);
-               e = -ENOMEM;
-               goto out;
-       }
-
-       e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS,
-               0, sz, (u64) objbuf, 0, 0, NULL);
-       if (e != SN_HWPERF_OP_OK) {
-               e = -EINVAL;
-               vfree(objbuf);
-       }
-
-out:
-       *nobj = sn_hwperf_obj_cnt;
-       *ret = objbuf;
-       return e;
-}
-
-static int sn_hwperf_location_to_bpos(char *location,
-       int *rack, int *bay, int *slot, int *slab)
-{
-       char type;
-
-       /* first scan for an old style geoid string */
-       if (sscanf(location, "%03d%c%02d#%d",
-               rack, &type, bay, slab) == 4)
-               *slot = 0; 
-       else /* scan for a new bladed geoid string */
-       if (sscanf(location, "%03d%c%02d^%02d#%d",
-               rack, &type, bay, slot, slab) != 5)
-               return -1; 
-       /* success */
-       return 0;
-}
-
-static int sn_hwperf_geoid_to_cnode(char *location)
-{
-       int cnode;
-       geoid_t geoid;
-       moduleid_t module_id;
-       int rack, bay, slot, slab;
-       int this_rack, this_bay, this_slot, this_slab;
-
-       if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
-               return -1;
-
-       /*
-        * FIXME: replace with cleaner for_each_XXX macro which addresses
-        * both compute and IO nodes once ACPI3.0 is available.
-        */
-       for (cnode = 0; cnode < num_cnodes; cnode++) {
-               geoid = cnodeid_get_geoid(cnode);
-               module_id = geo_module(geoid);
-               this_rack = MODULE_GET_RACK(module_id);
-               this_bay = MODULE_GET_BPOS(module_id);
-               this_slot = geo_slot(geoid);
-               this_slab = geo_slab(geoid);
-               if (rack == this_rack && bay == this_bay &&
-                       slot == this_slot && slab == this_slab) {
-                       break;
-               }
-       }
-
-       return cnode_possible(cnode) ? cnode : -1;
-}
-
-static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
-{
-       if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
-               BUG();
-       if (SN_HWPERF_FOREIGN(obj))
-               return -1;
-       return sn_hwperf_geoid_to_cnode(obj->location);
-}
-
-static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj,
-                               struct sn_hwperf_object_info *objs)
-{
-       int ordinal;
-       struct sn_hwperf_object_info *p;
-
-       for (ordinal=0, p=objs; p != obj; p++) {
-               if (SN_HWPERF_FOREIGN(p))
-                       continue;
-               if (SN_HWPERF_SAME_OBJTYPE(p, obj))
-                       ordinal++;
-       }
-
-       return ordinal;
-}
-
-static const char *slabname_node =     "node"; /* SHub asic */
-static const char *slabname_ionode =   "ionode"; /* TIO asic */
-static const char *slabname_router =   "router"; /* NL3R or NL4R */
-static const char *slabname_other =    "other"; /* unknown asic */
-
-static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj,
-                       struct sn_hwperf_object_info *objs, int *ordinal)
-{
-       int isnode;
-       const char *slabname = slabname_other;
-
-       if ((isnode = SN_HWPERF_IS_NODE(obj)) || SN_HWPERF_IS_IONODE(obj)) {
-               slabname = isnode ? slabname_node : slabname_ionode;
-               *ordinal = sn_hwperf_obj_to_cnode(obj);
-       }
-       else {
-               *ordinal = sn_hwperf_generic_ordinal(obj, objs);
-               if (SN_HWPERF_IS_ROUTER(obj))
-                       slabname = slabname_router;
-       }
-
-       return slabname;
-}
-
-static void print_pci_topology(struct seq_file *s)
-{
-       char *p;
-       size_t sz;
-       int e;
-
-       for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
-               if (!(p = kmalloc(sz, GFP_KERNEL)))
-                       break;
-               e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);
-               if (e == SALRET_OK)
-                       seq_puts(s, p);
-               kfree(p);
-               if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED)
-                       break;
-       }
-}
-
-static inline int sn_hwperf_has_cpus(cnodeid_t node)
-{
-       return node < MAX_NUMNODES && node_online(node) && nr_cpus_node(node);
-}
-
-static inline int sn_hwperf_has_mem(cnodeid_t node)
-{
-       return node < MAX_NUMNODES && node_online(node) && NODE_DATA(node)->node_present_pages;
-}
-
-static struct sn_hwperf_object_info *
-sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf,
-       int nobj, int id)
-{
-       int i;
-       struct sn_hwperf_object_info *p = objbuf;
-
-       for (i=0; i < nobj; i++, p++) {
-               if (p->id == id)
-                       return p;
-       }
-
-       return NULL;
-
-}
-
-static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf,
-       int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
-{
-       int e;
-       struct sn_hwperf_object_info *nodeobj = NULL;
-       struct sn_hwperf_object_info *op;
-       struct sn_hwperf_object_info *dest;
-       struct sn_hwperf_object_info *router;
-       struct sn_hwperf_port_info ptdata[16];
-       int sz, i, j;
-       cnodeid_t c;
-       int found_mem = 0;
-       int found_cpu = 0;
-
-       if (!cnode_possible(node))
-               return -EINVAL;
-
-       if (sn_hwperf_has_cpus(node)) {
-               if (near_cpu_node)
-                       *near_cpu_node = node;
-               found_cpu++;
-       }
-
-       if (sn_hwperf_has_mem(node)) {
-               if (near_mem_node)
-                       *near_mem_node = node;
-               found_mem++;
-       }
-
-       if (found_cpu && found_mem)
-               return 0; /* trivially successful */
-
-       /* find the argument node object */
-       for (i=0, op=objbuf; i < nobj; i++, op++) {
-               if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op))
-                       continue;
-               if (node == sn_hwperf_obj_to_cnode(op)) {
-                       nodeobj = op;
-                       break;
-               }
-       }
-       if (!nodeobj) {
-               e = -ENOENT;
-               goto err;
-       }
-
-       /* get it's interconnect topology */
-       sz = op->ports * sizeof(struct sn_hwperf_port_info);
-       BUG_ON(sz > sizeof(ptdata));
-       e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                             SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
-                             (u64)&ptdata, 0, 0, NULL);
-       if (e != SN_HWPERF_OP_OK) {
-               e = -EINVAL;
-               goto err;
-       }
-
-       /* find nearest node with cpus and nearest memory */
-       for (router=NULL, j=0; j < op->ports; j++) {
-               dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id);
-               if (dest && SN_HWPERF_IS_ROUTER(dest))
-                       router = dest;
-               if (!dest || SN_HWPERF_FOREIGN(dest) ||
-                   !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) {
-                       continue;
-               }
-               c = sn_hwperf_obj_to_cnode(dest);
-               if (!found_cpu && sn_hwperf_has_cpus(c)) {
-                       if (near_cpu_node)
-                               *near_cpu_node = c;
-                       found_cpu++;
-               }
-               if (!found_mem && sn_hwperf_has_mem(c)) {
-                       if (near_mem_node)
-                               *near_mem_node = c;
-                       found_mem++;
-               }
-       }
-
-       if (router && (!found_cpu || !found_mem)) {
-               /* search for a node connected to the same router */
-               sz = router->ports * sizeof(struct sn_hwperf_port_info);
-               BUG_ON(sz > sizeof(ptdata));
-               e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                                     SN_HWPERF_ENUM_PORTS, router->id, sz,
-                                     (u64)&ptdata, 0, 0, NULL);
-               if (e != SN_HWPERF_OP_OK) {
-                       e = -EINVAL;
-                       goto err;
-               }
-               for (j=0; j < router->ports; j++) {
-                       dest = sn_hwperf_findobj_id(objbuf, nobj,
-                               ptdata[j].conn_id);
-                       if (!dest || dest->id == node ||
-                           SN_HWPERF_FOREIGN(dest) ||
-                           !SN_HWPERF_IS_NODE(dest) ||
-                           SN_HWPERF_IS_IONODE(dest)) {
-                               continue;
-                       }
-                       c = sn_hwperf_obj_to_cnode(dest);
-                       if (!found_cpu && sn_hwperf_has_cpus(c)) {
-                               if (near_cpu_node)
-                                       *near_cpu_node = c;
-                               found_cpu++;
-                       }
-                       if (!found_mem && sn_hwperf_has_mem(c)) {
-                               if (near_mem_node)
-                                       *near_mem_node = c;
-                               found_mem++;
-                       }
-                       if (found_cpu && found_mem)
-                               break;
-               }
-       }
-
-       if (!found_cpu || !found_mem) {
-               /* resort to _any_ node with CPUs and memory */
-               for (i=0, op=objbuf; i < nobj; i++, op++) {
-                       if (SN_HWPERF_FOREIGN(op) ||
-                           SN_HWPERF_IS_IONODE(op) ||
-                           !SN_HWPERF_IS_NODE(op)) {
-                               continue;
-                       }
-                       c = sn_hwperf_obj_to_cnode(op);
-                       if (!found_cpu && sn_hwperf_has_cpus(c)) {
-                               if (near_cpu_node)
-                                       *near_cpu_node = c;
-                               found_cpu++;
-                       }
-                       if (!found_mem && sn_hwperf_has_mem(c)) {
-                               if (near_mem_node)
-                                       *near_mem_node = c;
-                               found_mem++;
-                       }
-                       if (found_cpu && found_mem)
-                               break;
-               }
-       }
-
-       if (!found_cpu || !found_mem)
-               e = -ENODATA;
-
-err:
-       return e;
-}
-
-
-static int sn_topology_show(struct seq_file *s, void *d)
-{
-       int sz;
-       int pt;
-       int e = 0;
-       int i;
-       int j;
-       const char *slabname;
-       int ordinal;
-       char slice;
-       struct cpuinfo_ia64 *c;
-       struct sn_hwperf_port_info *ptdata;
-       struct sn_hwperf_object_info *p;
-       struct sn_hwperf_object_info *obj = d;  /* this object */
-       struct sn_hwperf_object_info *objs = s->private; /* all objects */
-       u8 shubtype;
-       u8 system_size;
-       u8 sharing_size;
-       u8 partid;
-       u8 coher;
-       u8 nasid_shift;
-       u8 region_size;
-       u16 nasid_mask;
-       int nasid_msb;
-
-       if (obj == objs) {
-               seq_printf(s, "# sn_topology version 2\n");
-               seq_printf(s, "# objtype ordinal location partition"
-                       " [attribute value [, ...]]\n");
-
-               if (ia64_sn_get_sn_info(0,
-                       &shubtype, &nasid_mask, &nasid_shift, &system_size,
-                       &sharing_size, &partid, &coher, &region_size))
-                       BUG();
-               for (nasid_msb=63; nasid_msb > 0; nasid_msb--) {
-                       if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb))
-                               break;
-               }
-               seq_printf(s, "partition %u %s local "
-                       "shubtype %s, "
-                       "nasid_mask 0x%016llx, "
-                       "nasid_bits %d:%d, "
-                       "system_size %d, "
-                       "sharing_size %d, "
-                       "coherency_domain %d, "
-                       "region_size %d\n",
-
-                       partid, utsname()->nodename,
-                       shubtype ? "shub2" : "shub1", 
-                       (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
-                       system_size, sharing_size, coher, region_size);
-
-               print_pci_topology(s);
-       }
-
-       if (SN_HWPERF_FOREIGN(obj)) {
-               /* private in another partition: not interesting */
-               return 0;
-       }
-
-       for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) {
-               if (obj->name[i] == ' ')
-                       obj->name[i] = '_';
-       }
-
-       slabname = sn_hwperf_get_slabname(obj, objs, &ordinal);
-       seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location,
-               obj->sn_hwp_this_part ? "local" : "shared", obj->name);
-
-       if (ordinal < 0 || (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)))
-               seq_putc(s, '\n');
-       else {
-               cnodeid_t near_mem = -1;
-               cnodeid_t near_cpu = -1;
-
-               seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
-
-               if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt,
-                       ordinal, &near_mem, &near_cpu) == 0) {
-                       seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d",
-                               near_mem, near_cpu);
-               }
-
-               if (!SN_HWPERF_IS_IONODE(obj)) {
-                       for_each_online_node(i) {
-                               seq_printf(s, i ? ":%d" : ", dist %d",
-                                       node_distance(ordinal, i));
-                       }
-               }
-
-               seq_putc(s, '\n');
-
-               /*
-                * CPUs on this node, if any
-                */
-               if (!SN_HWPERF_IS_IONODE(obj)) {
-                       for_each_cpu_and(i, cpu_online_mask,
-                                        cpumask_of_node(ordinal)) {
-                               slice = 'a' + cpuid_to_slice(i);
-                               c = cpu_data(i);
-                               seq_printf(s, "cpu %d %s%c local"
-                                          " freq %luMHz, arch ia64",
-                                          i, obj->location, slice,
-                                          c->proc_freq / 1000000);
-                               for_each_online_cpu(j) {
-                                       seq_printf(s, j ? ":%d" : ", dist %d",
-                                                  node_distance(
-                                                       cpu_to_node(i),
-                                                       cpu_to_node(j)));
-                               }
-                               seq_putc(s, '\n');
-                       }
-               }
-       }
-
-       if (obj->ports) {
-               /*
-                * numalink ports
-                */
-               sz = obj->ports * sizeof(struct sn_hwperf_port_info);
-               if ((ptdata = kmalloc(sz, GFP_KERNEL)) == NULL)
-                       return -ENOMEM;
-               e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                                     SN_HWPERF_ENUM_PORTS, obj->id, sz,
-                                     (u64) ptdata, 0, 0, NULL);
-               if (e != SN_HWPERF_OP_OK)
-                       return -EINVAL;
-               for (ordinal=0, p=objs; p != obj; p++) {
-                       if (!SN_HWPERF_FOREIGN(p))
-                               ordinal += p->ports;
-               }
-               for (pt = 0; pt < obj->ports; pt++) {
-                       for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) {
-                               if (ptdata[pt].conn_id == p->id) {
-                                       break;
-                               }
-                       }
-                       seq_printf(s, "numalink %d %s-%d",
-                           ordinal+pt, obj->location, ptdata[pt].port);
-
-                       if (i >= sn_hwperf_obj_cnt) {
-                               /* no connection */
-                               seq_puts(s, " local endpoint disconnected"
-                                           ", protocol unknown\n");
-                               continue;
-                       }
-
-                       if (obj->sn_hwp_this_part && p->sn_hwp_this_part)
-                               /* both ends local to this partition */
-                               seq_puts(s, " local");
-                       else if (SN_HWPERF_FOREIGN(p))
-                               /* both ends of the link in foreign partition */
-                               seq_puts(s, " foreign");
-                       else
-                               /* link straddles a partition */
-                               seq_puts(s, " shared");
-
-                       /*
-                        * Unlikely, but strictly should query the LLP config
-                        * registers because an NL4R can be configured to run
-                        * NL3 protocol, even when not talking to an NL3 router.
-                        * Ditto for node-node.
-                        */
-                       seq_printf(s, " endpoint %s-%d, protocol %s\n",
-                               p->location, ptdata[pt].conn_port,
-                               (SN_HWPERF_IS_NL3ROUTER(obj) ||
-                               SN_HWPERF_IS_NL3ROUTER(p)) ?  "LLP3" : "LLP4");
-               }
-               kfree(ptdata);
-       }
-
-       return 0;
-}
-
-static void *sn_topology_start(struct seq_file *s, loff_t * pos)
-{
-       struct sn_hwperf_object_info *objs = s->private;
-
-       if (*pos < sn_hwperf_obj_cnt)
-               return (void *)(objs + *pos);
-
-       return NULL;
-}
-
-static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos)
-{
-       ++*pos;
-       return sn_topology_start(s, pos);
-}
-
-static void sn_topology_stop(struct seq_file *m, void *v)
-{
-       return;
-}
-
-/*
- * /proc/sgi_sn/sn_topology, read-only using seq_file
- */
-static const struct seq_operations sn_topology_seq_ops = {
-       .start = sn_topology_start,
-       .next = sn_topology_next,
-       .stop = sn_topology_stop,
-       .show = sn_topology_show
-};
-
-struct sn_hwperf_op_info {
-       u64 op;
-       struct sn_hwperf_ioctl_args *a;
-       void *p;
-       int *v0;
-       int ret;
-};
-
-static void sn_hwperf_call_sal(void *info)
-{
-       struct sn_hwperf_op_info *op_info = info;
-       int r;
-
-       r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op,
-                     op_info->a->arg, op_info->a->sz,
-                     (u64) op_info->p, 0, 0, op_info->v0);
-       op_info->ret = r;
-}
-
-static long sn_hwperf_call_sal_work(void *info)
-{
-       sn_hwperf_call_sal(info);
-       return 0;
-}
-
-static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
-{
-       u32 cpu;
-       u32 use_ipi;
-       int r = 0;
-       
-       cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32;
-       use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK;
-       op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
-
-       if (cpu != SN_HWPERF_ARG_ANY_CPU) {
-               if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
-                       r = -EINVAL;
-                       goto out;
-               }
-       }
-
-       if (cpu == SN_HWPERF_ARG_ANY_CPU) {
-               /* don't care which cpu */
-               sn_hwperf_call_sal(op_info);
-       } else if (cpu == get_cpu()) {
-               /* already on correct cpu */
-               sn_hwperf_call_sal(op_info);
-               put_cpu();
-       } else {
-               put_cpu();
-               if (use_ipi) {
-                       /* use an interprocessor interrupt to call SAL */
-                       smp_call_function_single(cpu, sn_hwperf_call_sal,
-                               op_info, 1);
-               } else {
-                       /* Call on the target CPU */
-                       work_on_cpu_safe(cpu, sn_hwperf_call_sal_work, op_info);
-               }
-       }
-       r = op_info->ret;
-
-out:
-       return r;
-}
-
-/* map SAL hwperf error code to system error code */
-static int sn_hwperf_map_err(int hwperf_err)
-{
-       int e;
-
-       switch(hwperf_err) {
-       case SN_HWPERF_OP_OK:
-               e = 0;
-               break;
-
-       case SN_HWPERF_OP_NOMEM:
-               e = -ENOMEM;
-               break;
-
-       case SN_HWPERF_OP_NO_PERM:
-               e = -EPERM;
-               break;
-
-       case SN_HWPERF_OP_IO_ERROR:
-               e = -EIO;
-               break;
-
-       case SN_HWPERF_OP_BUSY:
-               e = -EBUSY;
-               break;
-
-       case SN_HWPERF_OP_RECONFIGURE:
-               e = -EAGAIN;
-               break;
-
-       case SN_HWPERF_OP_INVAL:
-       default:
-               e = -EINVAL;
-               break;
-       }
-
-       return e;
-}
-
-/*
- * ioctl for "sn_hwperf" misc device
- */
-static long sn_hwperf_ioctl(struct file *fp, u32 op, unsigned long arg)
-{
-       struct sn_hwperf_ioctl_args a;
-       struct cpuinfo_ia64 *cdata;
-       struct sn_hwperf_object_info *objs;
-       struct sn_hwperf_object_info *cpuobj;
-       struct sn_hwperf_op_info op_info;
-       void *p = NULL;
-       int nobj;
-       char slice;
-       int node;
-       int r;
-       int v0;
-       int i;
-       int j;
-
-       /* only user requests are allowed here */
-       if ((op & SN_HWPERF_OP_MASK) < 10) {
-               r = -EINVAL;
-               goto error;
-       }
-       r = copy_from_user(&a, (const void __user *)arg,
-               sizeof(struct sn_hwperf_ioctl_args));
-       if (r != 0) {
-               r = -EFAULT;
-               goto error;
-       }
-
-       /*
-        * Allocate memory to hold a kernel copy of the user buffer. The
-        * buffer contents are either copied in or out (or both) of user
-        * space depending on the flags encoded in the requested operation.
-        */
-       if (a.ptr) {
-               p = vmalloc(a.sz);
-               if (!p) {
-                       r = -ENOMEM;
-                       goto error;
-               }
-       }
-
-       if (op & SN_HWPERF_OP_MEM_COPYIN) {
-               r = copy_from_user(p, (const void __user *)a.ptr, a.sz);
-               if (r != 0) {
-                       r = -EFAULT;
-                       goto error;
-               }
-       }
-
-       switch (op) {
-       case SN_HWPERF_GET_CPU_INFO:
-               if (a.sz == sizeof(u64)) {
-                       /* special case to get size needed */
-                       *(u64 *) p = (u64) num_online_cpus() *
-                               sizeof(struct sn_hwperf_object_info);
-               } else
-               if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) {
-                       r = -ENOMEM;
-                       goto error;
-               } else
-               if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
-                       int cpuobj_index = 0;
-
-                       memset(p, 0, a.sz);
-                       for (i = 0; i < nobj; i++) {
-                               if (!SN_HWPERF_IS_NODE(objs + i))
-                                       continue;
-                               node = sn_hwperf_obj_to_cnode(objs + i);
-                               for_each_online_cpu(j) {
-                                       if (node != cpu_to_node(j))
-                                               continue;
-                                       cpuobj = (struct sn_hwperf_object_info *) p + cpuobj_index++;
-                                       slice = 'a' + cpuid_to_slice(j);
-                                       cdata = cpu_data(j);
-                                       cpuobj->id = j;
-                                       snprintf(cpuobj->name,
-                                                sizeof(cpuobj->name),
-                                                "CPU %luMHz %s",
-                                                cdata->proc_freq / 1000000,
-                                                cdata->vendor);
-                                       snprintf(cpuobj->location,
-                                                sizeof(cpuobj->location),
-                                                "%s%c", objs[i].location,
-                                                slice);
-                               }
-                       }
-
-                       vfree(objs);
-               }
-               break;
-
-       case SN_HWPERF_GET_NODE_NASID:
-               if (a.sz != sizeof(u64) ||
-                  (node = a.arg) < 0 || !cnode_possible(node)) {
-                       r = -EINVAL;
-                       goto error;
-               }
-               *(u64 *)p = (u64)cnodeid_to_nasid(node);
-               break;
-
-       case SN_HWPERF_GET_OBJ_NODE:
-               i = a.arg;
-               if (a.sz != sizeof(u64) || i < 0) {
-                       r = -EINVAL;
-                       goto error;
-               }
-               if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
-                       if (i >= nobj) {
-                               r = -EINVAL;
-                               vfree(objs);
-                               goto error;
-                       }
-                       if (objs[i].id != a.arg) {
-                               for (i = 0; i < nobj; i++) {
-                                       if (objs[i].id == a.arg)
-                                               break;
-                               }
-                       }
-                       if (i == nobj) {
-                               r = -EINVAL;
-                               vfree(objs);
-                               goto error;
-                       }
-
-                       if (!SN_HWPERF_IS_NODE(objs + i) &&
-                           !SN_HWPERF_IS_IONODE(objs + i)) {
-                               r = -ENOENT;
-                               vfree(objs);
-                               goto error;
-                       }
-
-                       *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);
-                       vfree(objs);
-               }
-               break;
-
-       case SN_HWPERF_GET_MMRS:
-       case SN_HWPERF_SET_MMRS:
-       case SN_HWPERF_OBJECT_DISTANCE:
-               op_info.p = p;
-               op_info.a = &a;
-               op_info.v0 = &v0;
-               op_info.op = op;
-               r = sn_hwperf_op_cpu(&op_info);
-               if (r) {
-                       r = sn_hwperf_map_err(r);
-                       a.v0 = v0;
-                       goto error;
-               }
-               break;
-
-       default:
-               /* all other ops are a direct SAL call */
-               r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op,
-                             a.arg, a.sz, (u64) p, 0, 0, &v0);
-               if (r) {
-                       r = sn_hwperf_map_err(r);
-                       goto error;
-               }
-               a.v0 = v0;
-               break;
-       }
-
-       if (op & SN_HWPERF_OP_MEM_COPYOUT) {
-               r = copy_to_user((void __user *)a.ptr, p, a.sz);
-               if (r != 0) {
-                       r = -EFAULT;
-                       goto error;
-               }
-       }
-
-error:
-       vfree(p);
-
-       return r;
-}
-
-static const struct file_operations sn_hwperf_fops = {
-       .unlocked_ioctl = sn_hwperf_ioctl,
-       .llseek = noop_llseek,
-};
-
-static struct miscdevice sn_hwperf_dev = {
-       MISC_DYNAMIC_MINOR,
-       "sn_hwperf",
-       &sn_hwperf_fops
-};
-
-static int sn_hwperf_init(void)
-{
-       u64 v;
-       int salr;
-       int e = 0;
-
-       /* single threaded, once-only initialization */
-       mutex_lock(&sn_hwperf_init_mutex);
-
-       if (sn_hwperf_salheap) {
-               mutex_unlock(&sn_hwperf_init_mutex);
-               return e;
-       }
-
-       /*
-        * The PROM code needs a fixed reference node. For convenience the
-        * same node as the console I/O is used.
-        */
-       sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid();
-
-       /*
-        * Request the needed size and install the PROM scratch area.
-        * The PROM keeps various tracking bits in this memory area.
-        */
-       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                                (u64) SN_HWPERF_GET_HEAPSIZE, 0,
-                                (u64) sizeof(u64), (u64) &v, 0, 0, NULL);
-       if (salr != SN_HWPERF_OP_OK) {
-               e = -EINVAL;
-               goto out;
-       }
-
-       if ((sn_hwperf_salheap = vmalloc(v)) == NULL) {
-               e = -ENOMEM;
-               goto out;
-       }
-       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                                SN_HWPERF_INSTALL_HEAP, 0, v,
-                                (u64) sn_hwperf_salheap, 0, 0, NULL);
-       if (salr != SN_HWPERF_OP_OK) {
-               e = -EINVAL;
-               goto out;
-       }
-
-       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
-                                SN_HWPERF_OBJECT_COUNT, 0,
-                                sizeof(u64), (u64) &v, 0, 0, NULL);
-       if (salr != SN_HWPERF_OP_OK) {
-               e = -EINVAL;
-               goto out;
-       }
-       sn_hwperf_obj_cnt = (int)v;
-
-out:
-       if (e < 0 && sn_hwperf_salheap) {
-               vfree(sn_hwperf_salheap);
-               sn_hwperf_salheap = NULL;
-               sn_hwperf_obj_cnt = 0;
-       }
-       mutex_unlock(&sn_hwperf_init_mutex);
-       return e;
-}
-
-int sn_topology_open(struct inode *inode, struct file *file)
-{
-       int e;
-       struct seq_file *seq;
-       struct sn_hwperf_object_info *objbuf;
-       int nobj;
-
-       if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
-               e = seq_open(file, &sn_topology_seq_ops);
-               seq = file->private_data;
-               seq->private = objbuf;
-       }
-
-       return e;
-}
-
-int sn_topology_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *seq = file->private_data;
-
-       vfree(seq->private);
-       return seq_release(inode, file);
-}
-
-int sn_hwperf_get_nearest_node(cnodeid_t node,
-       cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
-{
-       int e;
-       int nobj;
-       struct sn_hwperf_object_info *objbuf;
-
-       if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
-               e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj,
-                       node, near_mem_node, near_cpu_node);
-               vfree(objbuf);
-       }
-
-       return e;
-}
-
-static int sn_hwperf_misc_register_init(void)
-{
-       int e;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       sn_hwperf_init();
-
-       /*
-        * Register a dynamic misc device for hwperf ioctls. Platforms
-        * supporting hotplug will create /dev/sn_hwperf, else user
-        * can to look up the minor number in /proc/misc.
-        */
-       if ((e = misc_register(&sn_hwperf_dev)) != 0) {
-               printk(KERN_ERR "sn_hwperf_misc_register_init: failed to "
-               "register misc device for \"%s\"\n", sn_hwperf_dev.name);
-       }
-
-       return e;
-}
-
-device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */
-EXPORT_SYMBOL(sn_hwperf_get_nearest_node);
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
deleted file mode 100644 (file)
index c2a4d84..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <asm/sn/sn_sal.h>
-
-static int partition_id_show(struct seq_file *s, void *p)
-{
-       seq_printf(s, "%d\n", sn_partition_id);
-       return 0;
-}
-
-static int system_serial_number_show(struct seq_file *s, void *p)
-{
-       seq_printf(s, "%s\n", sn_system_serial_number());
-       return 0;
-}
-
-static int licenseID_show(struct seq_file *s, void *p)
-{
-       seq_printf(s, "0x%llx\n", sn_partition_serial_number_val());
-       return 0;
-}
-
-static int coherence_id_show(struct seq_file *s, void *p)
-{
-       seq_printf(s, "%d\n", partition_coherence_id());
-
-       return 0;
-}
-
-/* /proc/sgi_sn/sn_topology uses seq_file, see sn_hwperf.c */
-extern int sn_topology_open(struct inode *, struct file *);
-extern int sn_topology_release(struct inode *, struct file *);
-
-static const struct file_operations proc_sn_topo_fops = {
-       .open           = sn_topology_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = sn_topology_release,
-};
-
-void register_sn_procfs(void)
-{
-       static struct proc_dir_entry *sgi_proc_dir = NULL;
-
-       BUG_ON(sgi_proc_dir != NULL);
-       if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL)))
-               return;
-
-       proc_create_single("partition_id", 0444, sgi_proc_dir,
-                       partition_id_show);
-       proc_create_single("system_serial_number", 0444, sgi_proc_dir,
-                       system_serial_number_show);
-       proc_create_single("licenseID", 0444, sgi_proc_dir, licenseID_show);
-       proc_create_single("coherence_id", 0444, sgi_proc_dir,
-                       coherence_id_show);
-       proc_create("sn_topology", 0444, sgi_proc_dir, &proc_sn_topo_fops);
-}
-
-#endif /* CONFIG_PROC_FS */
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
deleted file mode 100644 (file)
index 3009d9d..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/arch/ia64/sn/kernel/sn2/timer.c
- *
- * Copyright (C) 2003 Silicon Graphics, Inc.
- * Copyright (C) 2003 Hewlett-Packard Co
- *     David Mosberger <davidm@hpl.hp.com>: updated for new timer-interpolation infrastructure
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/clocksource.h>
-
-#include <asm/hw_irq.h>
-#include <asm/timex.h>
-
-#include <asm/sn/leds.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/clksupport.h>
-
-extern unsigned long sn_rtc_cycles_per_second;
-
-static u64 read_sn2(struct clocksource *cs)
-{
-       return (u64)readq(RTC_COUNTER_ADDR);
-}
-
-static struct clocksource clocksource_sn2 = {
-        .name           = "sn2_rtc",
-        .rating         = 450,
-        .read           = read_sn2,
-        .mask           = (1LL << 55) - 1,
-        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
- * sn udelay uses the RTC instead of the ITC because the ITC is not
- * synchronized across all CPUs, and the thread may migrate to another CPU
- * if preemption is enabled.
- */
-static void
-ia64_sn_udelay (unsigned long usecs)
-{
-       unsigned long start = rtc_time();
-       unsigned long end = start +
-                       usecs * sn_rtc_cycles_per_second / 1000000;
-
-       while (time_before((unsigned long)rtc_time(), end))
-               cpu_relax();
-}
-
-void __init sn_timer_init(void)
-{
-       clocksource_sn2.archdata.fsys_mmio = RTC_COUNTER_ADDR;
-       clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second);
-
-       ia64_udelay = &ia64_sn_udelay;
-}
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
deleted file mode 100644 (file)
index 103d6ea..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- *
- * Copyright (c) 2005, 2006 Silicon Graphics, Inc.  All Rights Reserved.
- * 
- * This program is free software; you can redistribute it and/or modify it 
- * under the terms of version 2 of the GNU General Public License 
- * as published by the Free Software Foundation.
- * 
- * This program is distributed in the hope that it would be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
- * 
- * Further, this software is distributed without any warranty that it is 
- * free of the rightful claim of any third person regarding infringement 
- * or the like.  Any license provided herein, whether implied or 
- * otherwise, applies only to this software file.  Patent licenses, if 
- * any, provided herein do not apply to combinations of this program with 
- * other software, or any other product whatsoever.
- * 
- * You should have received a copy of the GNU General Public 
- * License along with this program; if not, write the Free Software 
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- * 
- * For further information regarding this notice, see: 
- * 
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/interrupt.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/leds.h>
-
-extern void sn_lb_int_war_check(void);
-extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-#define SN_LB_INT_WAR_INTERVAL 100
-
-void sn_timer_interrupt(int irq, void *dev_id)
-{
-       /* LED blinking */
-       if (!pda->hb_count--) {
-               pda->hb_count = HZ / 2;
-               set_led_bits(pda->hb_state ^=
-                            LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT);
-       }
-
-       if (is_shub1()) {
-               if (enable_shub_wars_1_1()) {
-                       /* Bugfix code for SHUB 1.1 */
-                       if (pda->pio_shub_war_cam_addr)
-                               *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
-               }
-               if (pda->sn_lb_int_war_ticks == 0)
-                       sn_lb_int_war_check();
-               pda->sn_lb_int_war_ticks++;
-               if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
-                       pda->sn_lb_int_war_ticks = 0;
-       }
-}
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
deleted file mode 100644 (file)
index 32d0380..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/proc_fs.h>
-#include <linux/capability.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/uaccess.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/types.h>
-#include <asm/sn/shubio.h>
-#include <asm/sn/tiocx.h>
-#include <asm/sn/l1.h>
-#include <asm/sn/module.h>
-#include "tio.h"
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-
-#define CX_DEV_NONE 0
-#define DEVICE_NAME "tiocx"
-#define WIDGET_ID 0
-#define TIOCX_DEBUG 0
-
-#if TIOCX_DEBUG
-#define DBG(fmt...)    printk(KERN_ALERT fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-struct device_attribute dev_attr_cxdev_control;
-
-/**
- * tiocx_match - Try to match driver id list with device.
- * @dev: device pointer
- * @drv: driver pointer
- *
- * Returns 1 if match, 0 otherwise.
- */
-static int tiocx_match(struct device *dev, struct device_driver *drv)
-{
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       struct cx_drv *cx_drv = to_cx_driver(drv);
-       const struct cx_device_id *ids = cx_drv->id_table;
-
-       if (!ids)
-               return 0;
-
-       while (ids->part_num) {
-               if (ids->part_num == cx_dev->cx_id.part_num)
-                       return 1;
-               ids++;
-       }
-       return 0;
-
-}
-
-static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       return -ENODEV;
-}
-
-static void tiocx_bus_release(struct device *dev)
-{
-       kfree(to_cx_dev(dev));
-}
-
-/**
- * cx_device_match - Find cx_device in the id table.
- * @ids: id table from driver
- * @cx_device: part/mfg id for the device
- *
- */
-static const struct cx_device_id *cx_device_match(const struct cx_device_id
-                                                 *ids,
-                                                 struct cx_dev *cx_device)
-{
-       /*
-        * NOTES: We may want to check for CX_ANY_ID too.
-        *        Do we want to match against nasid too?
-        *        CX_DEV_NONE == 0, if the driver tries to register for
-        *        part/mfg == 0 we should return no-match (NULL) here.
-        */
-       while (ids->part_num && ids->mfg_num) {
-               if (ids->part_num == cx_device->cx_id.part_num &&
-                   ids->mfg_num == cx_device->cx_id.mfg_num)
-                       return ids;
-               ids++;
-       }
-
-       return NULL;
-}
-
-/**
- * cx_device_probe - Look for matching device.
- *                     Call driver probe routine if found.
- * @cx_driver: driver table (cx_drv struct) from driver
- * @cx_device: part/mfg id for the device
- */
-static int cx_device_probe(struct device *dev)
-{
-       const struct cx_device_id *id;
-       struct cx_drv *cx_drv = to_cx_driver(dev->driver);
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       int error = 0;
-
-       if (!cx_dev->driver && cx_drv->probe) {
-               id = cx_device_match(cx_drv->id_table, cx_dev);
-               if (id) {
-                       if ((error = cx_drv->probe(cx_dev, id)) < 0)
-                               return error;
-                       else
-                               cx_dev->driver = cx_drv;
-               }
-       }
-
-       return error;
-}
-
-/**
- * cx_driver_remove - Remove driver from device struct.
- * @dev: device
- */
-static int cx_driver_remove(struct device *dev)
-{
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       struct cx_drv *cx_drv = cx_dev->driver;
-       if (cx_drv->remove)
-               cx_drv->remove(cx_dev);
-       cx_dev->driver = NULL;
-       return 0;
-}
-
-struct bus_type tiocx_bus_type = {
-       .name = "tiocx",
-       .match = tiocx_match,
-       .uevent = tiocx_uevent,
-       .probe = cx_device_probe,
-       .remove = cx_driver_remove,
-};
-
-/**
- * cx_driver_register - Register the driver.
- * @cx_driver: driver table (cx_drv struct) from driver
- * 
- * Called from the driver init routine to register a driver.
- * The cx_drv struct contains the driver name, a pointer to
- * a table of part/mfg numbers and a pointer to the driver's
- * probe/attach routine.
- */
-int cx_driver_register(struct cx_drv *cx_driver)
-{
-       cx_driver->driver.name = cx_driver->name;
-       cx_driver->driver.bus = &tiocx_bus_type;
-
-       return driver_register(&cx_driver->driver);
-}
-
-/**
- * cx_driver_unregister - Unregister the driver.
- * @cx_driver: driver table (cx_drv struct) from driver
- */
-int cx_driver_unregister(struct cx_drv *cx_driver)
-{
-       driver_unregister(&cx_driver->driver);
-       return 0;
-}
-
-/**
- * cx_device_register - Register a device.
- * @nasid: device's nasid
- * @part_num: device's part number
- * @mfg_num: device's manufacturer number
- * @hubdev: hub info associated with this device
- * @bt: board type of the device
- *
- */
-int
-cx_device_register(nasid_t nasid, int part_num, int mfg_num,
-                  struct hubdev_info *hubdev, int bt)
-{
-       struct cx_dev *cx_dev;
-       int r;
-
-       cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL);
-       DBG("cx_dev= 0x%p\n", cx_dev);
-       if (cx_dev == NULL)
-               return -ENOMEM;
-
-       cx_dev->cx_id.part_num = part_num;
-       cx_dev->cx_id.mfg_num = mfg_num;
-       cx_dev->cx_id.nasid = nasid;
-       cx_dev->hubdev = hubdev;
-       cx_dev->bt = bt;
-
-       cx_dev->dev.parent = NULL;
-       cx_dev->dev.bus = &tiocx_bus_type;
-       cx_dev->dev.release = tiocx_bus_release;
-       dev_set_name(&cx_dev->dev, "%d", cx_dev->cx_id.nasid);
-       r = device_register(&cx_dev->dev);
-       if (r) {
-               kfree(cx_dev);
-               return r;
-       }
-       get_device(&cx_dev->dev);
-
-       device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
-
-       return 0;
-}
-
-/**
- * cx_device_unregister - Unregister a device.
- * @cx_dev: part/mfg id for the device
- */
-int cx_device_unregister(struct cx_dev *cx_dev)
-{
-       put_device(&cx_dev->dev);
-       device_unregister(&cx_dev->dev);
-       return 0;
-}
-
-/**
- * cx_device_reload - Reload the device.
- * @nasid: device's nasid
- * @part_num: device's part number
- * @mfg_num: device's manufacturer number
- *
- * Remove the device associated with 'nasid' from device list and then
- * call device-register with the given part/mfg numbers.
- */
-static int cx_device_reload(struct cx_dev *cx_dev)
-{
-       cx_device_unregister(cx_dev);
-       return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
-                                 cx_dev->cx_id.mfg_num, cx_dev->hubdev,
-                                 cx_dev->bt);
-}
-
-static inline u64 tiocx_intr_alloc(nasid_t nasid, int widget,
-                                       u64 sn_irq_info,
-                                       int req_irq, nasid_t req_nasid,
-                                       int req_slice)
-{
-       struct ia64_sal_retval rv;
-       rv.status = 0;
-       rv.v0 = 0;
-
-       ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
-                               SAL_INTR_ALLOC, nasid,
-                               widget, sn_irq_info, req_irq,
-                               req_nasid, req_slice);
-       return rv.status;
-}
-
-static inline void tiocx_intr_free(nasid_t nasid, int widget,
-                                  struct sn_irq_info *sn_irq_info)
-{
-       struct ia64_sal_retval rv;
-       rv.status = 0;
-       rv.v0 = 0;
-
-       ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
-                               SAL_INTR_FREE, nasid,
-                               widget, sn_irq_info->irq_irq,
-                               sn_irq_info->irq_cookie, 0, 0);
-}
-
-struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq,
-                                   nasid_t req_nasid, int slice)
-{
-       struct sn_irq_info *sn_irq_info;
-       int status;
-       int sn_irq_size = sizeof(struct sn_irq_info);
-
-       if ((nasid & 1) == 0)
-               return NULL;
-
-       sn_irq_info = kzalloc(sn_irq_size, GFP_KERNEL);
-       if (sn_irq_info == NULL)
-               return NULL;
-
-       status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq,
-                                 req_nasid, slice);
-       if (status) {
-               kfree(sn_irq_info);
-               return NULL;
-       } else {
-               return sn_irq_info;
-       }
-}
-
-void tiocx_irq_free(struct sn_irq_info *sn_irq_info)
-{
-       u64 bridge = (u64) sn_irq_info->irq_bridge;
-       nasid_t nasid = NASID_GET(bridge);
-       int widget;
-
-       if (nasid & 1) {
-               widget = TIO_SWIN_WIDGETNUM(bridge);
-               tiocx_intr_free(nasid, widget, sn_irq_info);
-               kfree(sn_irq_info);
-       }
-}
-
-u64 tiocx_dma_addr(u64 addr)
-{
-       return PHYS_TO_TIODMA(addr);
-}
-
-u64 tiocx_swin_base(int nasid)
-{
-       return TIO_SWIN_BASE(nasid, TIOCX_CORELET);
-}
-
-EXPORT_SYMBOL(cx_driver_register);
-EXPORT_SYMBOL(cx_driver_unregister);
-EXPORT_SYMBOL(cx_device_register);
-EXPORT_SYMBOL(cx_device_unregister);
-EXPORT_SYMBOL(tiocx_irq_alloc);
-EXPORT_SYMBOL(tiocx_irq_free);
-EXPORT_SYMBOL(tiocx_bus_type);
-EXPORT_SYMBOL(tiocx_dma_addr);
-EXPORT_SYMBOL(tiocx_swin_base);
-
-static void tio_conveyor_set(nasid_t nasid, int enable_flag)
-{
-       u64 ice_frz;
-       u64 disable_cb = (1ull << 61);
-
-       if (!(nasid & 1))
-               return;
-
-       ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG);
-       if (enable_flag) {
-               if (!(ice_frz & disable_cb))    /* already enabled */
-                       return;
-               ice_frz &= ~disable_cb;
-       } else {
-               if (ice_frz & disable_cb)       /* already disabled */
-                       return;
-               ice_frz |= disable_cb;
-       }
-       DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz);
-       REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz);
-}
-
-#define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1)
-#define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0)
-
-static void tio_corelet_reset(nasid_t nasid, int corelet)
-{
-       if (!(nasid & 1))
-               return;
-
-       REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet);
-       udelay(2000);
-       REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0);
-       udelay(2000);
-}
-
-static int is_fpga_tio(int nasid, int *bt)
-{
-       u16 uninitialized_var(ioboard_type);    /* GCC be quiet */
-       long rc;
-
-       rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard_type);
-       if (rc) {
-               printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n",
-                      rc);
-               return 0;
-       }
-
-       switch (ioboard_type) {
-       case L1_BRICKTYPE_SA:
-       case L1_BRICKTYPE_ATHENA:
-       case L1_BOARDTYPE_DAYTONA:
-               *bt = ioboard_type;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int bitstream_loaded(nasid_t nasid)
-{
-       u64 cx_credits;
-
-       cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3);
-       cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK;
-       DBG("cx_credits= 0x%lx\n", cx_credits);
-
-       return (cx_credits == 0xf) ? 1 : 0;
-}
-
-static int tiocx_reload(struct cx_dev *cx_dev)
-{
-       int part_num = CX_DEV_NONE;
-       int mfg_num = CX_DEV_NONE;
-       nasid_t nasid = cx_dev->cx_id.nasid;
-
-       if (bitstream_loaded(nasid)) {
-               u64 cx_id;
-               int rv;
-
-               rv = ia64_sn_sysctl_tio_clock_reset(nasid);
-               if (rv) {
-                       printk(KERN_ALERT "CX port JTAG reset failed.\n");
-               } else {
-                       cx_id = *(volatile u64 *)
-                               (TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
-                                         WIDGET_ID);
-                       part_num = XWIDGET_PART_NUM(cx_id);
-                       mfg_num = XWIDGET_MFG_NUM(cx_id);
-                       DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num);
-                       /* just ignore it if it's a CE */
-                       if (part_num == TIO_CE_ASIC_PARTNUM)
-                               return 0;
-               }
-       }
-
-       cx_dev->cx_id.part_num = part_num;
-       cx_dev->cx_id.mfg_num = mfg_num;
-
-       /*
-        * Delete old device and register the new one.  It's ok if
-        * part_num/mfg_num == CX_DEV_NONE.  We want to register
-        * devices in the table even if a bitstream isn't loaded.
-        * That allows use to see that a bitstream isn't loaded via
-        * TIOCX_IOCTL_DEV_LIST.
-        */
-       return cx_device_reload(cx_dev);
-}
-
-static ssize_t show_cxdev_control(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-
-       return sprintf(buf, "0x%x 0x%x 0x%x 0x%x\n",
-                      cx_dev->cx_id.nasid,
-                      cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num,
-                      cx_dev->bt);
-}
-
-static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *attr, const char *buf,
-                                  size_t count)
-{
-       int n;
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       if (count <= 0)
-               return 0;
-
-       n = simple_strtoul(buf, NULL, 0);
-
-       switch (n) {
-       case 1:
-               tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
-               tiocx_reload(cx_dev);
-               break;
-       case 2:
-               tiocx_reload(cx_dev);
-               break;
-       case 3:
-               tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
-               break;
-       default:
-               break;
-       }
-
-       return count;
-}
-
-DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
-
-static int __init tiocx_init(void)
-{
-       cnodeid_t cnodeid;
-       int found_tiocx_device = 0;
-       int err;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       err = bus_register(&tiocx_bus_type);
-       if (err)
-               return err;
-
-       for (cnodeid = 0; cnodeid < num_cnodes; cnodeid++) {
-               nasid_t nasid;
-               int bt;
-
-               nasid = cnodeid_to_nasid(cnodeid);
-
-               if ((nasid & 0x1) && is_fpga_tio(nasid, &bt)) {
-                       struct hubdev_info *hubdev;
-                       struct xwidget_info *widgetp;
-
-                       DBG("Found TIO at nasid 0x%x\n", nasid);
-
-                       hubdev =
-                           (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
-
-                       widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
-
-                       /* The CE hangs off of the CX port but is not an FPGA */
-                       if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM)
-                               continue;
-
-                       tio_corelet_reset(nasid, TIOCX_CORELET);
-                       tio_conveyor_enable(nasid);
-
-                       if (cx_device_register
-                           (nasid, widgetp->xwi_hwid.part_num,
-                            widgetp->xwi_hwid.mfg_num, hubdev, bt) < 0)
-                               return -ENXIO;
-                       else
-                               found_tiocx_device++;
-               }
-       }
-
-       /* It's ok if we find zero devices. */
-       DBG("found_tiocx_device= %d\n", found_tiocx_device);
-
-       return 0;
-}
-
-static int cx_remove_device(struct device * dev, void * data)
-{
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       device_remove_file(dev, &dev_attr_cxdev_control);
-       cx_device_unregister(cx_dev);
-       return 0;
-}
-
-static void __exit tiocx_exit(void)
-{
-       DBG("tiocx_exit\n");
-
-       /*
-        * Unregister devices.
-        */
-       bus_for_each_dev(&tiocx_bus_type, NULL, NULL, cx_remove_device);
-       bus_unregister(&tiocx_bus_type);
-}
-
-fs_initcall(tiocx_init);
-module_exit(tiocx_exit);
-
-/************************************************************************
- * Module licensing and description
- ************************************************************************/
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
-MODULE_DESCRIPTION("TIOCX module");
-MODULE_SUPPORTED_DEVICE(DEVICE_NAME);
diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile
deleted file mode 100644 (file)
index 321576b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
-#
-# Makefile for the sn pci general routines.
-
-obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
deleted file mode 100644 (file)
index b7d42e4..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
- *
- * Routines for PCI DMA mapping.  See Documentation/DMA-API.txt for
- * a description of how these routines should be used.
- */
-
-#include <linux/gfp.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <asm/dma.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/sn_sal.h>
-
-#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
-#define SG_ENT_PHYS_ADDRESS(SG)        virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
-
-/**
- * sn_dma_supported - test a DMA mask
- * @dev: device to test
- * @mask: DMA mask to test
- *
- * Return whether the given PCI device DMA address mask can be supported
- * properly.  For example, if your device can only drive the low 24-bits
- * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
- * this function.  Of course, SN only supports devices that have 32 or more
- * address bits when using the PMU.
- */
-static int sn_dma_supported(struct device *dev, u64 mask)
-{
-       BUG_ON(!dev_is_pci(dev));
-
-       if (mask < 0x7fffffff)
-               return 0;
-       return 1;
-}
-
-/**
- * sn_dma_set_mask - set the DMA mask
- * @dev: device to set
- * @dma_mask: new mask
- *
- * Set @dev's DMA mask if the hw supports it.
- */
-int sn_dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       BUG_ON(!dev_is_pci(dev));
-
-       if (!sn_dma_supported(dev, dma_mask))
-               return 0;
-
-       *dev->dma_mask = dma_mask;
-       return 1;
-}
-EXPORT_SYMBOL(sn_dma_set_mask);
-
-/**
- * sn_dma_alloc_coherent - allocate memory for coherent DMA
- * @dev: device to allocate for
- * @size: size of the region
- * @dma_handle: DMA (bus) address
- * @flags: memory allocation flags
- *
- * dma_alloc_coherent() returns a pointer to a memory region suitable for
- * coherent DMA traffic to/from a PCI device.  On SN platforms, this means
- * that @dma_handle will have the %PCIIO_DMA_CMD flag set.
- *
- * This interface is usually used for "command" streams (e.g. the command
- * queue for a SCSI controller).  See Documentation/DMA-API.txt for
- * more information.
- */
-static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
-                                  dma_addr_t * dma_handle, gfp_t flags,
-                                  unsigned long attrs)
-{
-       void *cpuaddr;
-       unsigned long phys_addr;
-       int node;
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       BUG_ON(!dev_is_pci(dev));
-
-       /*
-        * Allocate the memory.
-        */
-       node = pcibus_to_node(pdev->bus);
-       if (likely(node >=0)) {
-               struct page *p = __alloc_pages_node(node,
-                                               flags, get_order(size));
-
-               if (likely(p))
-                       cpuaddr = page_address(p);
-               else
-                       return NULL;
-       } else
-               cpuaddr = (void *)__get_free_pages(flags, get_order(size));
-
-       if (unlikely(!cpuaddr))
-               return NULL;
-
-       memset(cpuaddr, 0x0, size);
-
-       /* physical addr. of the memory we just got */
-       phys_addr = __pa(cpuaddr);
-
-       /*
-        * 64 bit address translations should never fail.
-        * 32 bit translations can fail if there are insufficient mapping
-        * resources.
-        */
-
-       *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
-                                                  SN_DMA_ADDR_PHYS);
-       if (!*dma_handle) {
-               printk(KERN_ERR "%s: out of ATEs\n", __func__);
-               free_pages((unsigned long)cpuaddr, get_order(size));
-               return NULL;
-       }
-
-       return cpuaddr;
-}
-
-/**
- * sn_pci_free_coherent - free memory associated with coherent DMAable region
- * @dev: device to free for
- * @size: size to free
- * @cpu_addr: kernel virtual address to free
- * @dma_handle: DMA address associated with this region
- *
- * Frees the memory allocated by dma_alloc_coherent(), potentially unmapping
- * any associated IOMMU mappings.
- */
-static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                                dma_addr_t dma_handle, unsigned long attrs)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       BUG_ON(!dev_is_pci(dev));
-
-       provider->dma_unmap(pdev, dma_handle, 0);
-       free_pages((unsigned long)cpu_addr, get_order(size));
-}
-
-/**
- * sn_dma_map_single_attrs - map a single page for DMA
- * @dev: device to map for
- * @cpu_addr: kernel virtual address of the region to map
- * @size: size of the region
- * @direction: DMA direction
- * @attrs: optional dma attributes
- *
- * Map the region pointed to by @cpu_addr for DMA and return the
- * DMA address.
- *
- * We map this to the one step pcibr_dmamap_trans interface rather than
- * the two step pcibr_dmamap_alloc/pcibr_dmamap_addr because we have
- * no way of saving the dmamap handle from the alloc to later free
- * (which is pretty much unacceptable).
- *
- * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with
- * dma_map_consistent() so that writes force a flush of pending DMA.
- * (See "SGI Altix Architecture Considerations for Linux Device Drivers",
- * Document Number: 007-4763-001)
- *
- * TODO: simplify our interface;
- *       figure out how to save dmamap handle so can use two step.
- */
-static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page,
-                                 unsigned long offset, size_t size,
-                                 enum dma_data_direction dir,
-                                 unsigned long attrs)
-{
-       void *cpu_addr = page_address(page) + offset;
-       dma_addr_t dma_addr;
-       unsigned long phys_addr;
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       BUG_ON(!dev_is_pci(dev));
-
-       phys_addr = __pa(cpu_addr);
-       if (attrs & DMA_ATTR_WRITE_BARRIER)
-               dma_addr = provider->dma_map_consistent(pdev, phys_addr,
-                                                       size, SN_DMA_ADDR_PHYS);
-       else
-               dma_addr = provider->dma_map(pdev, phys_addr, size,
-                                            SN_DMA_ADDR_PHYS);
-
-       if (!dma_addr) {
-               printk(KERN_ERR "%s: out of ATEs\n", __func__);
-               return DMA_MAPPING_ERROR;
-       }
-       return dma_addr;
-}
-
-/**
- * sn_dma_unmap_single_attrs - unamp a DMA mapped page
- * @dev: device to sync
- * @dma_addr: DMA address to sync
- * @size: size of region
- * @direction: DMA direction
- * @attrs: optional dma attributes
- *
- * This routine is supposed to sync the DMA region specified
- * by @dma_handle into the coherence domain.  On SN, we're always cache
- * coherent, so we just need to free any ATEs associated with this mapping.
- */
-static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
-                             size_t size, enum dma_data_direction dir,
-                             unsigned long attrs)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-
-       BUG_ON(!dev_is_pci(dev));
-
-       provider->dma_unmap(pdev, dma_addr, dir);
-}
-
-/**
- * sn_dma_unmap_sg - unmap a DMA scatterlist
- * @dev: device to unmap
- * @sg: scatterlist to unmap
- * @nhwentries: number of scatterlist entries
- * @direction: DMA direction
- * @attrs: optional dma attributes
- *
- * Unmap a set of streaming mode DMA translations.
- */
-static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
-                           int nhwentries, enum dma_data_direction dir,
-                           unsigned long attrs)
-{
-       int i;
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-       struct scatterlist *sg;
-
-       BUG_ON(!dev_is_pci(dev));
-
-       for_each_sg(sgl, sg, nhwentries, i) {
-               provider->dma_unmap(pdev, sg->dma_address, dir);
-               sg->dma_address = (dma_addr_t) NULL;
-               sg->dma_length = 0;
-       }
-}
-
-/**
- * sn_dma_map_sg - map a scatterlist for DMA
- * @dev: device to map for
- * @sg: scatterlist to map
- * @nhwentries: number of entries
- * @direction: direction of the DMA transaction
- * @attrs: optional dma attributes
- *
- * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with
- * dma_map_consistent() so that writes force a flush of pending DMA.
- * (See "SGI Altix Architecture Considerations for Linux Device Drivers",
- * Document Number: 007-4763-001)
- *
- * Maps each entry of @sg for DMA.
- */
-static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
-                        int nhwentries, enum dma_data_direction dir,
-                        unsigned long attrs)
-{
-       unsigned long phys_addr;
-       struct scatterlist *saved_sg = sgl, *sg;
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-       int i;
-
-       BUG_ON(!dev_is_pci(dev));
-
-       /*
-        * Setup a DMA address for each entry in the scatterlist.
-        */
-       for_each_sg(sgl, sg, nhwentries, i) {
-               dma_addr_t dma_addr;
-               phys_addr = SG_ENT_PHYS_ADDRESS(sg);
-               if (attrs & DMA_ATTR_WRITE_BARRIER)
-                       dma_addr = provider->dma_map_consistent(pdev,
-                                                               phys_addr,
-                                                               sg->length,
-                                                               SN_DMA_ADDR_PHYS);
-               else
-                       dma_addr = provider->dma_map(pdev, phys_addr,
-                                                    sg->length,
-                                                    SN_DMA_ADDR_PHYS);
-
-               sg->dma_address = dma_addr;
-               if (!sg->dma_address) {
-                       printk(KERN_ERR "%s: out of ATEs\n", __func__);
-
-                       /*
-                        * Free any successfully allocated entries.
-                        */
-                       if (i > 0)
-                               sn_dma_unmap_sg(dev, saved_sg, i, dir, attrs);
-                       return 0;
-               }
-
-               sg->dma_length = sg->length;
-       }
-
-       return nhwentries;
-}
-
-static u64 sn_dma_get_required_mask(struct device *dev)
-{
-       return DMA_BIT_MASK(64);
-}
-
-char *sn_pci_get_legacy_mem(struct pci_bus *bus)
-{
-       if (!SN_PCIBUS_BUSSOFT(bus))
-               return ERR_PTR(-ENODEV);
-
-       return (char *)(SN_PCIBUS_BUSSOFT(bus)->bs_legacy_mem | __IA64_UNCACHED_OFFSET);
-}
-
-int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
-{
-       unsigned long addr;
-       int ret;
-       struct ia64_sal_retval isrv;
-
-       /*
-        * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work
-        * around hw issues at the pci bus level.  SGI proms older than
-        * 4.10 don't implement this.
-        */
-
-       SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE,
-                pci_domain_nr(bus), bus->number,
-                0, /* io */
-                0, /* read */
-                port, size, __pa(val));
-
-       if (isrv.status == 0)
-               return size;
-
-       /*
-        * If the above failed, retry using the SAL_PROBE call which should
-        * be present in all proms (but which cannot work round PCI chipset
-        * bugs).  This code is retained for compatibility with old
-        * pre-4.10 proms, and should be removed at some point in the future.
-        */
-
-       if (!SN_PCIBUS_BUSSOFT(bus))
-               return -ENODEV;
-
-       addr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET;
-       addr += port;
-
-       ret = ia64_sn_probe_mem(addr, (long)size, (void *)val);
-
-       if (ret == 2)
-               return -EINVAL;
-
-       if (ret == 1)
-               *val = -1;
-
-       return size;
-}
-
-int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
-{
-       int ret = size;
-       unsigned long paddr;
-       unsigned long *addr;
-       struct ia64_sal_retval isrv;
-
-       /*
-        * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work
-        * around hw issues at the pci bus level.  SGI proms older than
-        * 4.10 don't implement this.
-        */
-
-       SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE,
-                pci_domain_nr(bus), bus->number,
-                0, /* io */
-                1, /* write */
-                port, size, __pa(&val));
-
-       if (isrv.status == 0)
-               return size;
-
-       /*
-        * If the above failed, retry using the SAL_PROBE call which should
-        * be present in all proms (but which cannot work round PCI chipset
-        * bugs).  This code is retained for compatibility with old
-        * pre-4.10 proms, and should be removed at some point in the future.
-        */
-
-       if (!SN_PCIBUS_BUSSOFT(bus)) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       /* Put the phys addr in uncached space */
-       paddr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET;
-       paddr += port;
-       addr = (unsigned long *)paddr;
-
-       switch (size) {
-       case 1:
-               *(volatile u8 *)(addr) = (u8)(val);
-               break;
-       case 2:
-               *(volatile u16 *)(addr) = (u16)(val);
-               break;
-       case 4:
-               *(volatile u32 *)(addr) = (u32)(val);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
- out:
-       return ret;
-}
-
-static struct dma_map_ops sn_dma_ops = {
-       .alloc                  = sn_dma_alloc_coherent,
-       .free                   = sn_dma_free_coherent,
-       .map_page               = sn_dma_map_page,
-       .unmap_page             = sn_dma_unmap_page,
-       .map_sg                 = sn_dma_map_sg,
-       .unmap_sg               = sn_dma_unmap_sg,
-       .dma_supported          = sn_dma_supported,
-       .get_required_mask      = sn_dma_get_required_mask,
-};
-
-void sn_dma_init(void)
-{
-       dma_ops = &sn_dma_ops;
-}
diff --git a/arch/ia64/sn/pci/pcibr/Makefile b/arch/ia64/sn/pci/pcibr/Makefile
deleted file mode 100644 (file)
index 712f6af..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 2002-2004 Silicon Graphics, Inc.  All Rights Reserved.
-#
-# Makefile for the sn2 io routines.
-
-ccflags-y := -I $(srctree)/arch/ia64/sn/include
-
-obj-y                          +=  pcibr_dma.o pcibr_reg.o \
-                                   pcibr_ate.o pcibr_provider.o
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
deleted file mode 100644 (file)
index b67bb4c..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-
-int pcibr_invalidate_ate;      /* by default don't invalidate ATE on free */
-
-/*
- * mark_ate: Mark the ate as either free or inuse.
- */
-static void mark_ate(struct ate_resource *ate_resource, int start, int number,
-                    u64 value)
-{
-       u64 *ate = ate_resource->ate;
-       int index;
-       int length = 0;
-
-       for (index = start; length < number; index++, length++)
-               ate[index] = value;
-}
-
-/*
- * find_free_ate:  Find the first free ate index starting from the given
- *                index for the desired consecutive count.
- */
-static int find_free_ate(struct ate_resource *ate_resource, int start,
-                        int count)
-{
-       u64 *ate = ate_resource->ate;
-       int index;
-       int start_free;
-
-       for (index = start; index < ate_resource->num_ate;) {
-               if (!ate[index]) {
-                       int i;
-                       int free;
-                       free = 0;
-                       start_free = index;     /* Found start free ate */
-                       for (i = start_free; i < ate_resource->num_ate; i++) {
-                               if (!ate[i]) {  /* This is free */
-                                       if (++free == count)
-                                               return start_free;
-                               } else {
-                                       index = i + 1;
-                                       break;
-                               }
-                       }
-                       if (i >= ate_resource->num_ate)
-                               return -1;
-               } else
-                       index++;        /* Try next ate */
-       }
-
-       return -1;
-}
-
-/*
- * free_ate_resource:  Free the requested number of ATEs.
- */
-static inline void free_ate_resource(struct ate_resource *ate_resource,
-                                    int start)
-{
-       mark_ate(ate_resource, start, ate_resource->ate[start], 0);
-       if ((ate_resource->lowest_free_index > start) ||
-           (ate_resource->lowest_free_index < 0))
-               ate_resource->lowest_free_index = start;
-}
-
-/*
- * alloc_ate_resource:  Allocate the requested number of ATEs.
- */
-static inline int alloc_ate_resource(struct ate_resource *ate_resource,
-                                    int ate_needed)
-{
-       int start_index;
-
-       /*
-        * Check for ate exhaustion.
-        */
-       if (ate_resource->lowest_free_index < 0)
-               return -1;
-
-       /*
-        * Find the required number of free consecutive ates.
-        */
-       start_index =
-           find_free_ate(ate_resource, ate_resource->lowest_free_index,
-                         ate_needed);
-       if (start_index >= 0)
-               mark_ate(ate_resource, start_index, ate_needed, ate_needed);
-
-       ate_resource->lowest_free_index =
-           find_free_ate(ate_resource, ate_resource->lowest_free_index, 1);
-
-       return start_index;
-}
-
-/*
- * Allocate "count" contiguous Bridge Address Translation Entries
- * on the specified bridge to be used for PCI to XTALK mappings.
- * Indices in rm map range from 1..num_entries.  Indices returned
- * to caller range from 0..num_entries-1.
- *
- * Return the start index on success, -1 on failure.
- */
-int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count)
-{
-       int status;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pcibus_info->pbi_lock, flags);
-       status = alloc_ate_resource(&pcibus_info->pbi_int_ate_resource, count);
-       spin_unlock_irqrestore(&pcibus_info->pbi_lock, flags);
-
-       return status;
-}
-
-/*
- * Setup an Address Translation Entry as specified.  Use either the Bridge
- * internal maps or the external map RAM, as appropriate.
- */
-static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info,
-                                      int ate_index)
-{
-       if (ate_index < pcibus_info->pbi_int_ate_size) {
-               return pcireg_int_ate_addr(pcibus_info, ate_index);
-       }
-       panic("pcibr_ate_addr: invalid ate_index 0x%x", ate_index);
-}
-
-/*
- * Update the ate.
- */
-inline void
-ate_write(struct pcibus_info *pcibus_info, int ate_index, int count,
-         volatile u64 ate)
-{
-       while (count-- > 0) {
-               if (ate_index < pcibus_info->pbi_int_ate_size) {
-                       pcireg_int_ate_set(pcibus_info, ate_index, ate);
-               } else {
-                       panic("ate_write: invalid ate_index 0x%x", ate_index);
-               }
-               ate_index++;
-               ate += IOPGSIZE;
-       }
-
-       pcireg_tflush_get(pcibus_info); /* wait until Bridge PIO complete */
-}
-
-void pcibr_ate_free(struct pcibus_info *pcibus_info, int index)
-{
-
-       volatile u64 ate;
-       int count;
-       unsigned long flags;
-
-       if (pcibr_invalidate_ate) {
-               /* For debugging purposes, clear the valid bit in the ATE */
-               ate = *pcibr_ate_addr(pcibus_info, index);
-               count = pcibus_info->pbi_int_ate_resource.ate[index];
-               ate_write(pcibus_info, index, count, (ate & ~PCI32_ATE_V));
-       }
-
-       spin_lock_irqsave(&pcibus_info->pbi_lock, flags);
-       free_ate_resource(&pcibus_info->pbi_int_ate_resource, index);
-       spin_unlock_irqrestore(&pcibus_info->pbi_lock, flags);
-}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
deleted file mode 100644 (file)
index 1e863b2..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/export.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pic.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/tiocp.h>
-#include "tio.h"
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-
-extern int sn_ioif_inited;
-
-/* =====================================================================
- *    DMA MANAGEMENT
- *
- *      The Bridge ASIC provides three methods of doing DMA: via a "direct map"
- *      register available in 32-bit PCI space (which selects a contiguous 2G
- *     address space on some other widget), via "direct" addressing via 64-bit
- *      PCI space (all destination information comes from the PCI address,
- *      including transfer attributes), and via a "mapped" region that allows 
- *      a bunch of different small mappings to be established with the PMU.
- *
- *      For efficiency, we most prefer to use the 32bit direct mapping facility,
- *      since it requires no resource allocations. The advantage of using the
- *      PMU over the 64-bit direct is that single-cycle PCI addressing can be
- *      used; the advantage of using 64-bit direct over PMU addressing is that
- *      we do not have to allocate entries in the PMU.
- */
-
-static dma_addr_t
-pcibr_dmamap_ate32(struct pcidev_info *info,
-                  u64 paddr, size_t req_size, u64 flags, int dma_flags)
-{
-
-       struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
-       struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
-           pdi_pcibus_info;
-       u8 internal_device = (PCI_SLOT(pcidev_info->pdi_host_pcidev_info->
-                                           pdi_linux_pcidev->devfn)) - 1;
-       int ate_count;
-       int ate_index;
-       u64 ate_flags = flags | PCI32_ATE_V;
-       u64 ate;
-       u64 pci_addr;
-       u64 xio_addr;
-       u64 offset;
-
-       /* PIC in PCI-X mode does not supports 32bit PageMap mode */
-       if (IS_PIC_SOFT(pcibus_info) && IS_PCIX(pcibus_info)) {
-               return 0;
-       }
-
-       /* Calculate the number of ATEs needed. */
-       if (!(MINIMAL_ATE_FLAG(paddr, req_size))) {
-               ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */
-                                +req_size      /* max mapping bytes */
-                                - 1) + 1;      /* round UP */
-       } else {                /* assume requested target is page aligned */
-               ate_count = IOPG(req_size       /* max mapping bytes */
-                                - 1) + 1;      /* round UP */
-       }
-
-       /* Get the number of ATEs required. */
-       ate_index = pcibr_ate_alloc(pcibus_info, ate_count);
-       if (ate_index < 0)
-               return 0;
-
-       /* In PCI-X mode, Prefetch not supported */
-       if (IS_PCIX(pcibus_info))
-               ate_flags &= ~(PCI32_ATE_PREF);
-
-       if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS))
-               xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
-                                                     PHYS_TO_TIODMA(paddr);
-       else
-               xio_addr = paddr;
-
-       offset = IOPGOFF(xio_addr);
-       ate = ate_flags | (xio_addr - offset);
-
-       /* If PIC, put the targetid in the ATE */
-       if (IS_PIC_SOFT(pcibus_info)) {
-               ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
-       }
-
-       /*
-        * If we're mapping for MSI, set the MSI bit in the ATE.  If it's a
-        * TIOCP based pci bus, we also need to set the PIO bit in the ATE.
-        */
-       if (dma_flags & SN_DMA_MSI) {
-               ate |= PCI32_ATE_MSI;
-               if (IS_TIOCP_SOFT(pcibus_info))
-                       ate |= PCI32_ATE_PIO;
-       }
-
-       ate_write(pcibus_info, ate_index, ate_count, ate);
-
-       /*
-        * Set up the DMA mapped Address.
-        */
-       pci_addr = PCI32_MAPPED_BASE + offset + IOPGSIZE * ate_index;
-
-       /*
-        * If swap was set in device in pcibr_endian_set()
-        * we need to turn swapping on.
-        */
-       if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
-               ATE_SWAP_ON(pci_addr);
-
-
-       return pci_addr;
-}
-
-static dma_addr_t
-pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
-                       u64 dma_attributes, int dma_flags)
-{
-       struct pcibus_info *pcibus_info = (struct pcibus_info *)
-           ((info->pdi_host_pcidev_info)->pdi_pcibus_info);
-       u64 pci_addr;
-
-       /* Translate to Crosstalk View of Physical Address */
-       if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
-               pci_addr = IS_PIC_SOFT(pcibus_info) ?
-                               PHYS_TO_DMA(paddr) :
-                               PHYS_TO_TIODMA(paddr);
-       else
-               pci_addr = paddr;
-       pci_addr |= dma_attributes;
-
-       /* Handle Bus mode */
-       if (IS_PCIX(pcibus_info))
-               pci_addr &= ~PCI64_ATTR_PREF;
-
-       /* Handle Bridge Chipset differences */
-       if (IS_PIC_SOFT(pcibus_info)) {
-               pci_addr |=
-                   ((u64) pcibus_info->
-                    pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
-       } else
-               pci_addr |= (dma_flags & SN_DMA_MSI) ?
-                               TIOCP_PCI64_CMDTYPE_MSI :
-                               TIOCP_PCI64_CMDTYPE_MEM;
-
-       /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
-       if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
-               pci_addr |= PCI64_ATTR_VIRTUAL;
-
-       return pci_addr;
-}
-
-static dma_addr_t
-pcibr_dmatrans_direct32(struct pcidev_info * info,
-                       u64 paddr, size_t req_size, u64 flags, int dma_flags)
-{
-       struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
-       struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
-           pdi_pcibus_info;
-       u64 xio_addr;
-
-       u64 xio_base;
-       u64 offset;
-       u64 endoff;
-
-       if (IS_PCIX(pcibus_info)) {
-               return 0;
-       }
-
-       if (dma_flags & SN_DMA_MSI)
-               return 0;
-
-       if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
-               xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
-                                                     PHYS_TO_TIODMA(paddr);
-       else
-               xio_addr = paddr;
-
-       xio_base = pcibus_info->pbi_dir_xbase;
-       offset = xio_addr - xio_base;
-       endoff = req_size + offset;
-       if ((req_size > (1ULL << 31)) ||        /* Too Big */
-           (xio_addr < xio_base) ||    /* Out of range for mappings */
-           (endoff > (1ULL << 31))) {  /* Too Big */
-               return 0;
-       }
-
-       return PCI32_DIRECT_BASE | offset;
-}
-
-/*
- * Wrapper routine for freeing DMA maps
- * DMA mappings for Direct 64 and 32 do not have any DMA maps.
- */
-void
-pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction)
-{
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
-       struct pcibus_info *pcibus_info =
-           (struct pcibus_info *)pcidev_info->pdi_pcibus_info;
-
-       if (IS_PCI32_MAPPED(dma_handle)) {
-               int ate_index;
-
-               ate_index =
-                   IOPG((ATE_SWAP_OFF(dma_handle) - PCI32_MAPPED_BASE));
-               pcibr_ate_free(pcibus_info, ate_index);
-       }
-}
-
-/*
- * On SN systems there is a race condition between a PIO read response and 
- * DMA's.  In rare cases, the read response may beat the DMA, causing the
- * driver to think that data in memory is complete and meaningful.  This code
- * eliminates that race.  This routine is called by the PIO read routines
- * after doing the read.  For PIC this routine then forces a fake interrupt
- * on another line, which is logically associated with the slot that the PIO
- * is addressed to.  It then spins while watching the memory location that
- * the interrupt is targeted to.  When the interrupt response arrives, we 
- * are sure that the DMA has landed in memory and it is safe for the driver
- * to proceed. For TIOCP use the Device(x) Write Request Buffer Flush 
- * Bridge register since it ensures the data has entered the coherence domain,
- * unlike the PIC Device(x) Write Request Buffer Flush register.
- */
-
-void sn_dma_flush(u64 addr)
-{
-       nasid_t nasid;
-       int is_tio;
-       int wid_num;
-       int i, j;
-       unsigned long flags;
-       u64 itte;
-       struct hubdev_info *hubinfo;
-       struct sn_flush_device_kernel *p;
-       struct sn_flush_device_common *common;
-       struct sn_flush_nasid_entry *flush_nasid_list;
-
-       if (!sn_ioif_inited)
-               return;
-
-       nasid = NASID_GET(addr);
-       if (-1 == nasid_to_cnodeid(nasid))
-               return;
-
-       hubinfo = (NODEPDA(nasid_to_cnodeid(nasid)))->pdinfo;
-
-       BUG_ON(!hubinfo);
-
-       flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
-       if (flush_nasid_list->widget_p == NULL)
-               return;
-
-       is_tio = (nasid & 1);
-       if (is_tio) {
-               int itte_index;
-
-               if (TIO_HWIN(addr))
-                       itte_index = 0;
-               else if (TIO_BWIN_WINDOWNUM(addr))
-                       itte_index = TIO_BWIN_WINDOWNUM(addr);
-               else
-                       itte_index = -1;
-
-               if (itte_index >= 0) {
-                       itte = flush_nasid_list->iio_itte[itte_index];
-                       if (! TIO_ITTE_VALID(itte))
-                               return;
-                       wid_num = TIO_ITTE_WIDGET(itte);
-               } else
-                       wid_num = TIO_SWIN_WIDGETNUM(addr);
-       } else {
-               if (BWIN_WINDOWNUM(addr)) {
-                       itte = flush_nasid_list->iio_itte[BWIN_WINDOWNUM(addr)];
-                       wid_num = IIO_ITTE_WIDGET(itte);
-               } else
-                       wid_num = SWIN_WIDGETNUM(addr);
-       }
-       if (flush_nasid_list->widget_p[wid_num] == NULL)
-               return;
-       p = &flush_nasid_list->widget_p[wid_num][0];
-
-       /* find a matching BAR */
-       for (i = 0; i < DEV_PER_WIDGET; i++,p++) {
-               common = p->common;
-               for (j = 0; j < PCI_ROM_RESOURCE; j++) {
-                       if (common->sfdl_bar_list[j].start == 0)
-                               break;
-                       if (addr >= common->sfdl_bar_list[j].start
-                           && addr <= common->sfdl_bar_list[j].end)
-                               break;
-               }
-               if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0)
-                       break;
-       }
-
-       /* if no matching BAR, return without doing anything. */
-       if (i == DEV_PER_WIDGET)
-               return;
-
-       /*
-        * For TIOCP use the Device(x) Write Request Buffer Flush Bridge
-        * register since it ensures the data has entered the coherence
-        * domain, unlike PIC.
-        */
-       if (is_tio) {
-               /*
-                * Note:  devices behind TIOCE should never be matched in the
-                * above code, and so the following code is PIC/CP centric.
-                * If CE ever needs the sn_dma_flush mechanism, we will have
-                * to account for that here and in tioce_bus_fixup().
-                */
-               u32 tio_id = HUB_L(TIO_IOSPACE_ADDR(nasid, TIO_NODE_ID));
-               u32 revnum = XWIDGET_PART_REV_NUM(tio_id);
-
-               /* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */
-               if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) {
-                       return;
-               } else {
-                       pcireg_wrb_flush_get(common->sfdl_pcibus_info,
-                                            (common->sfdl_slot - 1));
-               }
-       } else {
-               spin_lock_irqsave(&p->sfdl_flush_lock, flags);
-               *common->sfdl_flush_addr = 0;
-
-               /* force an interrupt. */
-               *(volatile u32 *)(common->sfdl_force_int_addr) = 1;
-
-               /* wait for the interrupt to come back. */
-               while (*(common->sfdl_flush_addr) != 0x10f)
-                       cpu_relax();
-
-               /* okay, everything is synched up. */
-               spin_unlock_irqrestore(&p->sfdl_flush_lock, flags);
-       }
-       return;
-}
-
-/*
- * DMA interfaces.  Called from pci_dma.c routines.
- */
-
-dma_addr_t
-pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags)
-{
-       dma_addr_t dma_handle;
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
-
-       /* SN cannot support DMA addresses smaller than 32 bits. */
-       if (hwdev->dma_mask < 0x7fffffff) {
-               return 0;
-       }
-
-       if (hwdev->dma_mask == ~0UL) {
-               /*
-                * Handle the most common case: 64 bit cards.  This
-                * call should always succeed.
-                */
-
-               dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-                                                    PCI64_ATTR_PREF, dma_flags);
-       } else {
-               /* Handle 32-63 bit cards via direct mapping */
-               dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
-                                                    size, 0, dma_flags);
-               if (!dma_handle) {
-                       /*
-                        * It is a 32 bit card and we cannot do direct mapping,
-                        * so we use an ATE.
-                        */
-
-                       dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
-                                                       size, PCI32_ATE_PREF,
-                                                       dma_flags);
-               }
-       }
-
-       return dma_handle;
-}
-
-dma_addr_t
-pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
-                        size_t size, int dma_flags)
-{
-       dma_addr_t dma_handle;
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
-
-       if (hwdev->dev.coherent_dma_mask == ~0UL) {
-               dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-                                           PCI64_ATTR_BAR, dma_flags);
-       } else {
-               dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
-                                                   phys_addr, size,
-                                                   PCI32_ATE_BAR, dma_flags);
-       }
-
-       return dma_handle;
-}
-
-EXPORT_SYMBOL(sn_dma_flush);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
deleted file mode 100644 (file)
index 7195df1..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001-2004, 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/export.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/pic.h>
-#include <asm/sn/sn2/sn_hwperf.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
-
-int
-sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,
-                      char **ssdt)
-{
-       struct ia64_sal_retval ret_stuff;
-       u64 busnum;
-       u64 segment;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       segment = soft->pbi_buscommon.bs_persist_segment;
-       busnum = soft->pbi_buscommon.bs_persist_busnum;
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,
-                       busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),
-                       0, 0);
-
-       return (int)ret_stuff.v0;
-}
-
-int
-sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action,
-                      void *resp)
-{
-       struct ia64_sal_retval ret_stuff;
-       u64 busnum;
-       u64 segment;
-
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       segment = soft->pbi_buscommon.bs_persist_segment;
-       busnum = soft->pbi_buscommon.bs_persist_busnum;
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE,
-                       segment, busnum, (u64) device, (u64) action,
-                       (u64) resp, 0, 0);
-
-       return (int)ret_stuff.v0;
-}
-
-static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
-{
-       struct ia64_sal_retval ret_stuff;
-       u64 busnum;
-       int segment;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       segment = soft->pbi_buscommon.bs_persist_segment;
-       busnum = soft->pbi_buscommon.bs_persist_busnum;
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
-                       (u64) segment, (u64) busnum, 0, 0, 0, 0, 0);
-
-       return (int)ret_stuff.v0;
-}
-
-u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)
-{
-       long rc;
-       u16 uninitialized_var(ioboard);         /* GCC be quiet */
-       nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base);
-
-       rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard);
-       if (rc) {
-               printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n",
-                      rc);
-               return 0;
-       }
-
-       return ioboard;
-}
-
-/* 
- * PCI Bridge Error interrupt handler.  Gets invoked whenever a PCI 
- * bridge sends an error interrupt.
- */
-static irqreturn_t
-pcibr_error_intr_handler(int irq, void *arg)
-{
-       struct pcibus_info *soft = arg;
-
-       if (sal_pcibr_error_interrupt(soft) < 0)
-               panic("pcibr_error_intr_handler(): Fatal Bridge Error");
-
-       return IRQ_HANDLED;
-}
-
-void *
-pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
-{
-       int nasid, cnode, j;
-       struct hubdev_info *hubdev_info;
-       struct pcibus_info *soft;
-       struct sn_flush_device_kernel *sn_flush_device_kernel;
-       struct sn_flush_device_common *common;
-
-       if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {
-               return NULL;
-       }
-
-       /*
-        * Allocate kernel bus soft and copy from prom.
-        */
-
-       soft = kmemdup(prom_bussoft, sizeof(struct pcibus_info), GFP_KERNEL);
-       if (!soft) {
-               return NULL;
-       }
-
-       soft->pbi_buscommon.bs_base = (unsigned long)
-               ioremap(REGION_OFFSET(soft->pbi_buscommon.bs_base),
-                       sizeof(struct pic));
-
-       spin_lock_init(&soft->pbi_lock);
-
-       /*
-        * register the bridge's error interrupt handler
-        */
-       if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler,
-                       IRQF_SHARED, "PCIBR error", (void *)(soft))) {
-               printk(KERN_WARNING
-                      "pcibr cannot allocate interrupt for error handler\n");
-       }
-       irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
-       sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
-
-       /* 
-        * Update the Bridge with the "kernel" pagesize 
-        */
-       if (PAGE_SIZE < 16384) {
-               pcireg_control_bit_clr(soft, PCIBR_CTRL_PAGE_SIZE);
-       } else {
-               pcireg_control_bit_set(soft, PCIBR_CTRL_PAGE_SIZE);
-       }
-
-       nasid = NASID_GET(soft->pbi_buscommon.bs_base);
-       cnode = nasid_to_cnodeid(nasid);
-       hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
-
-       if (hubdev_info->hdi_flush_nasid_list.widget_p) {
-               sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list.
-                   widget_p[(int)soft->pbi_buscommon.bs_xid];
-               if (sn_flush_device_kernel) {
-                       for (j = 0; j < DEV_PER_WIDGET;
-                            j++, sn_flush_device_kernel++) {
-                               common = sn_flush_device_kernel->common;
-                               if (common->sfdl_slot == -1)
-                                       continue;
-                               if ((common->sfdl_persistent_segment ==
-                                    soft->pbi_buscommon.bs_persist_segment) &&
-                                    (common->sfdl_persistent_busnum ==
-                                    soft->pbi_buscommon.bs_persist_busnum))
-                                       common->sfdl_pcibus_info =
-                                           soft;
-                       }
-               }
-       }
-
-       /* Setup the PMU ATE map */
-       soft->pbi_int_ate_resource.lowest_free_index = 0;
-       soft->pbi_int_ate_resource.ate =
-           kcalloc(soft->pbi_int_ate_size, sizeof(u64), GFP_KERNEL);
-
-       if (!soft->pbi_int_ate_resource.ate) {
-               kfree(soft);
-               return NULL;
-       }
-
-       return soft;
-}
-
-void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
-{
-       struct pcidev_info *pcidev_info;
-       struct pcibus_info *pcibus_info;
-       int bit = sn_irq_info->irq_int_bit;
-
-       if (! sn_irq_info->irq_bridge)
-               return;
-
-       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       if (pcidev_info) {
-               pcibus_info =
-                   (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
-                   pdi_pcibus_info;
-               pcireg_force_intr_set(pcibus_info, bit);
-       }
-}
-
-void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)
-{
-       struct pcidev_info *pcidev_info;
-       struct pcibus_info *pcibus_info;
-       int bit = sn_irq_info->irq_int_bit;
-       u64 xtalk_addr = sn_irq_info->irq_xtalkaddr;
-
-       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       if (pcidev_info) {
-               pcibus_info =
-                   (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
-                   pdi_pcibus_info;
-
-               /* Disable the device's IRQ   */
-               pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit));
-
-               /* Change the device's IRQ    */
-               pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr);
-
-               /* Re-enable the device's IRQ */
-               pcireg_intr_enable_bit_set(pcibus_info, (1 << bit));
-
-               pcibr_force_interrupt(sn_irq_info);
-       }
-}
-
-/*
- * Provider entries for PIC/CP
- */
-
-struct sn_pcibus_provider pcibr_provider = {
-       .dma_map = pcibr_dma_map,
-       .dma_map_consistent = pcibr_dma_map_consistent,
-       .dma_unmap = pcibr_dma_unmap,
-       .bus_fixup = pcibr_bus_fixup,
-       .force_interrupt = pcibr_force_interrupt,
-       .target_interrupt = pcibr_target_interrupt
-};
-
-int
-pcibr_init_provider(void)
-{
-       sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider;
-       sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider;
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);
-EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);
-EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
deleted file mode 100644 (file)
index 8b8bbd5..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <asm/sn/io.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pic.h>
-#include <asm/sn/tiocp.h>
-
-union br_ptr {
-       struct tiocp tio;
-       struct pic pic;
-};
-
-/*
- * Control Register Access -- Read/Write                            0000_0020
- */
-void pcireg_control_bit_clr(struct pcibus_info *pcibus_info, u64 bits)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       __sn_clrq_relaxed(&ptr->tio.cp_control, bits);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       __sn_clrq_relaxed(&ptr->pic.p_wid_control, bits);
-                       break;
-               default:
-                       panic
-                           ("pcireg_control_bit_clr: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-void pcireg_control_bit_set(struct pcibus_info *pcibus_info, u64 bits)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       __sn_setq_relaxed(&ptr->tio.cp_control, bits);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       __sn_setq_relaxed(&ptr->pic.p_wid_control, bits);
-                       break;
-               default:
-                       panic
-                           ("pcireg_control_bit_set: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-/*
- * PCI/PCIX Target Flush Register Access -- Read Only              0000_0050
- */
-u64 pcireg_tflush_get(struct pcibus_info *pcibus_info)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-       u64 ret = 0;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       ret = __sn_readq_relaxed(&ptr->tio.cp_tflush);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       ret = __sn_readq_relaxed(&ptr->pic.p_wid_tflush);
-                       break;
-               default:
-                       panic
-                           ("pcireg_tflush_get: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-
-       /* Read of the Target Flush should always return zero */
-       if (ret != 0)
-               panic("pcireg_tflush_get:Target Flush failed\n");
-
-       return ret;
-}
-
-/*
- * Interrupt Status Register Access -- Read Only                   0000_0100
- */
-u64 pcireg_intr_status_get(struct pcibus_info * pcibus_info)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-       u64 ret = 0;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       ret = __sn_readq_relaxed(&ptr->tio.cp_int_status);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       ret = __sn_readq_relaxed(&ptr->pic.p_int_status);
-                       break;
-               default:
-                       panic
-                           ("pcireg_intr_status_get: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-       return ret;
-}
-
-/*
- * Interrupt Enable Register Access -- Read/Write                   0000_0108
- */
-void pcireg_intr_enable_bit_clr(struct pcibus_info *pcibus_info, u64 bits)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       __sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       __sn_clrq_relaxed(&ptr->pic.p_int_enable, bits);
-                       break;
-               default:
-                       panic
-                           ("pcireg_intr_enable_bit_clr: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-void pcireg_intr_enable_bit_set(struct pcibus_info *pcibus_info, u64 bits)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       __sn_setq_relaxed(&ptr->tio.cp_int_enable, bits);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       __sn_setq_relaxed(&ptr->pic.p_int_enable, bits);
-                       break;
-               default:
-                       panic
-                           ("pcireg_intr_enable_bit_set: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-/*
- * Intr Host Address Register (int_addr) -- Read/Write  0000_0130 - 0000_0168
- */
-void pcireg_intr_addr_addr_set(struct pcibus_info *pcibus_info, int int_n,
-                              u64 addr)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       __sn_clrq_relaxed(&ptr->tio.cp_int_addr[int_n],
-                           TIOCP_HOST_INTR_ADDR);
-                       __sn_setq_relaxed(&ptr->tio.cp_int_addr[int_n],
-                           (addr & TIOCP_HOST_INTR_ADDR));
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       __sn_clrq_relaxed(&ptr->pic.p_int_addr[int_n],
-                           PIC_HOST_INTR_ADDR);
-                       __sn_setq_relaxed(&ptr->pic.p_int_addr[int_n],
-                           (addr & PIC_HOST_INTR_ADDR));
-                       break;
-               default:
-                       panic
-                           ("pcireg_intr_addr_addr_get: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-/*
- * Force Interrupt Register Access -- Write Only       0000_01C0 - 0000_01F8
- */
-void pcireg_force_intr_set(struct pcibus_info *pcibus_info, int int_n)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       writeq(1, &ptr->tio.cp_force_pin[int_n]);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       writeq(1, &ptr->pic.p_force_pin[int_n]);
-                       break;
-               default:
-                       panic
-                           ("pcireg_force_intr_set: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-/*
- * Device(x) Write Buffer Flush Reg Access -- Read Only 0000_0240 - 0000_0258
- */
-u64 pcireg_wrb_flush_get(struct pcibus_info *pcibus_info, int device)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-       u64 ret = 0;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       ret =
-                           __sn_readq_relaxed(&ptr->tio.cp_wr_req_buf[device]);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       ret =
-                           __sn_readq_relaxed(&ptr->pic.p_wr_req_buf[device]);
-                       break;
-               default:
-                     panic("pcireg_wrb_flush_get: unknown bridgetype bridge 0x%p", ptr);
-               }
-
-       }
-       /* Read of the Write Buffer Flush should always return zero */
-       return ret;
-}
-
-void pcireg_int_ate_set(struct pcibus_info *pcibus_info, int ate_index,
-                       u64 val)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       writeq(val, &ptr->tio.cp_int_ate_ram[ate_index]);
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       writeq(val, &ptr->pic.p_int_ate_ram[ate_index]);
-                       break;
-               default:
-                       panic
-                           ("pcireg_int_ate_set: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-}
-
-u64 __iomem *pcireg_int_ate_addr(struct pcibus_info *pcibus_info, int ate_index)
-{
-       union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
-       u64 __iomem *ret = NULL;
-
-       if (pcibus_info) {
-               switch (pcibus_info->pbi_bridge_type) {
-               case PCIBR_BRIDGETYPE_TIOCP:
-                       ret = &ptr->tio.cp_int_ate_ram[ate_index];
-                       break;
-               case PCIBR_BRIDGETYPE_PIC:
-                       ret = &ptr->pic.p_int_ate_ram[ate_index];
-                       break;
-               default:
-                       panic
-                           ("pcireg_int_ate_addr: unknown bridgetype bridge 0x%p",
-                            ptr);
-               }
-       }
-       return ret;
-}
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
deleted file mode 100644 (file)
index a70b11f..0000000
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/bitmap.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/tioca_provider.h>
-
-u32 tioca_gart_found;
-EXPORT_SYMBOL(tioca_gart_found);       /* used by agp-sgi */
-
-LIST_HEAD(tioca_list);
-EXPORT_SYMBOL(tioca_list);     /* used by agp-sgi */
-
-static int tioca_gart_init(struct tioca_kernel *);
-
-/**
- * tioca_gart_init - Initialize SGI TIOCA GART
- * @tioca_common: ptr to common prom/kernel struct identifying the 
- *
- * If the indicated tioca has devices present, initialize its associated
- * GART MMR's and kernel memory.
- */
-static int
-tioca_gart_init(struct tioca_kernel *tioca_kern)
-{
-       u64 ap_reg;
-       u64 offset;
-       struct page *tmp;
-       struct tioca_common *tioca_common;
-       struct tioca __iomem *ca_base;
-
-       tioca_common = tioca_kern->ca_common;
-       ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base;
-
-       if (list_empty(tioca_kern->ca_devices))
-               return 0;
-
-       ap_reg = 0;
-
-       /*
-        * Validate aperature size
-        */
-
-       switch (CA_APERATURE_SIZE >> 20) {
-       case 4:
-               ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT);      /* 4MB */
-               break;
-       case 8:
-               ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT);      /* 8MB */
-               break;
-       case 16:
-               ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT);      /* 16MB */
-               break;
-       case 32:
-               ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT);      /* 32 MB */
-               break;
-       case 64:
-               ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT);      /* 64 MB */
-               break;
-       case 128:
-               ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT);      /* 128 MB */
-               break;
-       case 256:
-               ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT);      /* 256 MB */
-               break;
-       case 512:
-               ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT);      /* 512 MB */
-               break;
-       case 1024:
-               ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT);      /* 1GB */
-               break;
-       case 2048:
-               ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT);      /* 2GB */
-               break;
-       case 4096:
-               ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT);      /* 4 GB */
-               break;
-       default:
-               printk(KERN_ERR "%s:  Invalid CA_APERATURE_SIZE "
-                      "0x%lx\n", __func__, (ulong) CA_APERATURE_SIZE);
-               return -1;
-       }
-
-       /*
-        * Set up other aperature parameters
-        */
-
-       if (PAGE_SIZE >= 16384) {
-               tioca_kern->ca_ap_pagesize = 16384;
-               ap_reg |= CA_GART_PAGE_SIZE;
-       } else {
-               tioca_kern->ca_ap_pagesize = 4096;
-       }
-
-       tioca_kern->ca_ap_size = CA_APERATURE_SIZE;
-       tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE;
-       tioca_kern->ca_gart_entries =
-           tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize;
-
-       ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI);
-       ap_reg |= tioca_kern->ca_ap_bus_base;
-
-       /*
-        * Allocate and set up the GART
-        */
-
-       tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64);
-       tmp =
-           alloc_pages_node(tioca_kern->ca_closest_node,
-                            GFP_KERNEL | __GFP_ZERO,
-                            get_order(tioca_kern->ca_gart_size));
-
-       if (!tmp) {
-               printk(KERN_ERR "%s:  Could not allocate "
-                      "%llu bytes (order %d) for GART\n",
-                      __func__,
-                      tioca_kern->ca_gart_size,
-                      get_order(tioca_kern->ca_gart_size));
-               return -ENOMEM;
-       }
-
-       tioca_kern->ca_gart = page_address(tmp);
-       tioca_kern->ca_gart_coretalk_addr =
-           PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart));
-
-       /*
-        * Compute PCI/AGP convenience fields 
-        */
-
-       offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE;
-       tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE;
-       tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE;
-       tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize;
-       tioca_kern->ca_pcigart_base =
-           tioca_kern->ca_gart_coretalk_addr + offset;
-       tioca_kern->ca_pcigart =
-           &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start];
-       tioca_kern->ca_pcigart_entries =
-           tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize;
-       tioca_kern->ca_pcigart_pagemap =
-           kzalloc(tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL);
-       if (!tioca_kern->ca_pcigart_pagemap) {
-               free_pages((unsigned long)tioca_kern->ca_gart,
-                          get_order(tioca_kern->ca_gart_size));
-               return -1;
-       }
-
-       offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE;
-       tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE;
-       tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE;
-       tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize;
-       tioca_kern->ca_gfxgart_base =
-           tioca_kern->ca_gart_coretalk_addr + offset;
-       tioca_kern->ca_gfxgart =
-           &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start];
-       tioca_kern->ca_gfxgart_entries =
-           tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize;
-
-       /*
-        * various control settings:
-        *      use agp op-combining
-        *      use GET semantics to fetch memory
-        *      participate in coherency domain
-        *      DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029
-        */
-
-       __sn_setq_relaxed(&ca_base->ca_control1,
-                       CA_AGPDMA_OP_ENB_COMBDELAY);    /* PV895469 ? */
-       __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM);
-       __sn_setq_relaxed(&ca_base->ca_control2,
-                       (0x2ull << CA_GART_MEM_PARAM_SHFT));
-       tioca_kern->ca_gart_iscoherent = 1;
-       __sn_clrq_relaxed(&ca_base->ca_control2,
-                       (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB));
-
-       /*
-        * Unmask GART fetch error interrupts.  Clear residual errors first.
-        */
-
-       writeq(CA_GART_FETCH_ERR, &ca_base->ca_int_status_alias);
-       writeq(CA_GART_FETCH_ERR, &ca_base->ca_mult_error_alias);
-       __sn_clrq_relaxed(&ca_base->ca_int_mask, CA_GART_FETCH_ERR);
-
-       /*
-        * Program the aperature and gart registers in TIOCA
-        */
-
-       writeq(ap_reg, &ca_base->ca_gart_aperature);
-       writeq(tioca_kern->ca_gart_coretalk_addr|1, &ca_base->ca_gart_ptr_table);
-
-       return 0;
-}
-
-/**
- * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions
- * @tioca_kernel: structure representing the CA
- *
- * Given a CA, scan all attached functions making sure they all support
- * FastWrite.  If so, enable FastWrite for all functions and the CA itself.
- */
-
-void
-tioca_fastwrite_enable(struct tioca_kernel *tioca_kern)
-{
-       int cap_ptr;
-       u32 reg;
-       struct tioca __iomem *tioca_base;
-       struct pci_dev *pdev;
-       struct tioca_common *common;
-
-       common = tioca_kern->ca_common;
-
-       /*
-        * Scan all vga controllers on this bus making sure they all
-        * support FW.  If not, return.
-        */
-
-       list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) {
-               if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
-                       continue;
-
-               cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
-               if (!cap_ptr)
-                       return; /* no AGP CAP means no FW */
-
-               pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, &reg);
-               if (!(reg & PCI_AGP_STATUS_FW))
-                       return; /* function doesn't support FW */
-       }
-
-       /*
-        * Set fw for all vga fn's
-        */
-
-       list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) {
-               if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
-                       continue;
-
-               cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
-               pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, &reg);
-               reg |= PCI_AGP_COMMAND_FW;
-               pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg);
-       }
-
-       /*
-        * Set ca's fw to match
-        */
-
-       tioca_base = (struct tioca __iomem*)common->ca_common.bs_base;
-       __sn_setq_relaxed(&tioca_base->ca_control1, CA_AGP_FW_ENABLE);
-}
-
-EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */
-
-/**
- * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode
- * @paddr: system physical address
- *
- * Map @paddr into 64-bit CA bus space.  No device context is necessary.
- * Bits 53:0 come from the coretalk address.  We just need to mask in the
- * following optional bits of the 64-bit pci address:
- *
- * 63:60 - Coretalk Packet Type -  0x1 for Mem Get/Put (coherent)
- *                                 0x2 for PIO (non-coherent)
- *                                 We will always use 0x1
- * 55:55 - Swap bytes             Currently unused
- */
-static u64
-tioca_dma_d64(unsigned long paddr)
-{
-       dma_addr_t bus_addr;
-
-       bus_addr = PHYS_TO_TIODMA(paddr);
-
-       BUG_ON(!bus_addr);
-       BUG_ON(bus_addr >> 54);
-
-       /* Set upper nibble to Cache Coherent Memory op */
-       bus_addr |= (1UL << 60);
-
-       return bus_addr;
-}
-
-/**
- * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode
- * @pdev: linux pci_dev representing the function
- * @paddr: system physical address
- *
- * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info.
- *
- * The CA agp 48 bit direct address falls out as follows:
- *
- * When direct mapping AGP addresses, the 48 bit AGP address is
- * constructed as follows:
- *
- * [47:40] - Low 8 bits of the page Node ID extracted from coretalk
- *              address [47:40].  The upper 8 node bits are fixed
- *              and come from the xxx register bits [5:0]
- * [39:38] - Chiplet ID extracted from coretalk address [39:38]
- * [37:00] - node offset extracted from coretalk address [37:00]
- * 
- * Since the node id in general will be non-zero, and the chiplet id
- * will always be non-zero, it follows that the device must support
- * a dma mask of at least 0xffffffffff (40 bits) to target node 0
- * and in general should be 0xffffffffffff (48 bits) to target nodes
- * up to 255.  Nodes above 255 need the support of the xxx register,
- * and so a given CA can only directly target nodes in the range
- * xxx - xxx+255.
- */
-static u64
-tioca_dma_d48(struct pci_dev *pdev, u64 paddr)
-{
-       struct tioca_common *tioca_common;
-       struct tioca __iomem *ca_base;
-       u64 ct_addr;
-       dma_addr_t bus_addr;
-       u32 node_upper;
-       u64 agp_dma_extn;
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);
-
-       tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
-       ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base;
-
-       ct_addr = PHYS_TO_TIODMA(paddr);
-       if (!ct_addr)
-               return 0;
-
-       bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffffUL);
-       node_upper = ct_addr >> 48;
-
-       if (node_upper > 64) {
-               printk(KERN_ERR "%s:  coretalk addr 0x%p node id out "
-                      "of range\n", __func__, (void *)ct_addr);
-               return 0;
-       }
-
-       agp_dma_extn = __sn_readq_relaxed(&ca_base->ca_agp_dma_addr_extn);
-       if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) {
-               printk(KERN_ERR "%s:  coretalk upper node (%u) "
-                      "mismatch with ca_agp_dma_addr_extn (%llu)\n",
-                      __func__,
-                      node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT));
-               return 0;
-       }
-
-       return bus_addr;
-}
-
-/**
- * tioca_dma_mapped - create a DMA mapping using a CA GART 
- * @pdev: linux pci_dev representing the function
- * @paddr: host physical address to map
- * @req_size: len (bytes) to map
- *
- * Map @paddr into CA address space using the GART mechanism.  The mapped
- * dma_addr_t is guaranteed to be contiguous in CA bus space.
- */
-static dma_addr_t
-tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size)
-{
-       int ps, ps_shift, entry, entries, mapsize;
-       u64 xio_addr, end_xio_addr;
-       struct tioca_common *tioca_common;
-       struct tioca_kernel *tioca_kern;
-       dma_addr_t bus_addr = 0;
-       struct tioca_dmamap *ca_dmamap;
-       void *map;
-       unsigned long flags;
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);
-
-       tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
-       tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;
-
-       xio_addr = PHYS_TO_TIODMA(paddr);
-       if (!xio_addr)
-               return 0;
-
-       spin_lock_irqsave(&tioca_kern->ca_lock, flags);
-
-       /*
-        * allocate a map struct
-        */
-
-       ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC);
-       if (!ca_dmamap)
-               goto map_return;
-
-       /*
-        * Locate free entries that can hold req_size.  Account for
-        * unaligned start/length when allocating.
-        */
-
-       ps = tioca_kern->ca_ap_pagesize;        /* will be power of 2 */
-       ps_shift = ffs(ps) - 1;
-       end_xio_addr = xio_addr + req_size - 1;
-
-       entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1;
-
-       map = tioca_kern->ca_pcigart_pagemap;
-       mapsize = tioca_kern->ca_pcigart_entries;
-
-       entry = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0);
-       if (entry >= mapsize) {
-               kfree(ca_dmamap);
-               goto map_return;
-       }
-
-       bitmap_set(map, entry, entries);
-
-       bus_addr = tioca_kern->ca_pciap_base + (entry * ps);
-
-       ca_dmamap->cad_dma_addr = bus_addr;
-       ca_dmamap->cad_gart_size = entries;
-       ca_dmamap->cad_gart_entry = entry;
-       list_add(&ca_dmamap->cad_list, &tioca_kern->ca_dmamaps);
-
-       if (xio_addr % ps) {
-               tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);
-               bus_addr += xio_addr & (ps - 1);
-               xio_addr &= ~(ps - 1);
-               xio_addr += ps;
-               entry++;
-       }
-
-       while (xio_addr < end_xio_addr) {
-               tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);
-               xio_addr += ps;
-               entry++;
-       }
-
-       tioca_tlbflush(tioca_kern);
-
-map_return:
-       spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);
-       return bus_addr;
-}
-
-/**
- * tioca_dma_unmap - release CA mapping resources
- * @pdev: linux pci_dev representing the function
- * @bus_addr: bus address returned by an earlier tioca_dma_map
- * @dir: mapping direction (unused)
- *
- * Locate mapping resources associated with @bus_addr and release them.
- * For mappings created using the direct modes (64 or 48) there are no
- * resources to release.
- */
-static void
-tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
-{
-       int i, entry;
-       struct tioca_common *tioca_common;
-       struct tioca_kernel *tioca_kern;
-       struct tioca_dmamap *map;
-       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);
-       unsigned long flags;
-
-       tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;
-       tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;
-
-       /* return straight away if this isn't be a mapped address */
-
-       if (bus_addr < tioca_kern->ca_pciap_base ||
-           bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size))
-               return;
-
-       spin_lock_irqsave(&tioca_kern->ca_lock, flags);
-
-       list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list)
-           if (map->cad_dma_addr == bus_addr)
-               break;
-
-       BUG_ON(map == NULL);
-
-       entry = map->cad_gart_entry;
-
-       for (i = 0; i < map->cad_gart_size; i++, entry++) {
-               clear_bit(entry, tioca_kern->ca_pcigart_pagemap);
-               tioca_kern->ca_pcigart[entry] = 0;
-       }
-       tioca_tlbflush(tioca_kern);
-
-       list_del(&map->cad_list);
-       spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);
-       kfree(map);
-}
-
-/**
- * tioca_dma_map - map pages for PCI DMA
- * @pdev: linux pci_dev representing the function
- * @paddr: host physical address to map
- * @byte_count: bytes to map
- *
- * This is the main wrapper for mapping host physical pages to CA PCI space.
- * The mapping mode used is based on the devices dma_mask.  As a last resort
- * use the GART mapped mode.
- */
-static u64
-tioca_dma_map(struct pci_dev *pdev, unsigned long paddr, size_t byte_count, int dma_flags)
-{
-       u64 mapaddr;
-
-       /*
-        * Not supported for now ...
-        */
-       if (dma_flags & SN_DMA_MSI)
-               return 0;
-
-       /*
-        * If card is 64 or 48 bit addressable, use a direct mapping.  32
-        * bit direct is so restrictive w.r.t. where the memory resides that
-        * we don't use it even though CA has some support.
-        */
-
-       if (pdev->dma_mask == ~0UL)
-               mapaddr = tioca_dma_d64(paddr);
-       else if (pdev->dma_mask == 0xffffffffffffUL)
-               mapaddr = tioca_dma_d48(pdev, paddr);
-       else
-               mapaddr = 0;
-
-       /* Last resort ... use PCI portion of CA GART */
-
-       if (mapaddr == 0)
-               mapaddr = tioca_dma_mapped(pdev, paddr, byte_count);
-
-       return mapaddr;
-}
-
-/**
- * tioca_error_intr_handler - SGI TIO CA error interrupt handler
- * @irq: unused
- * @arg: pointer to tioca_common struct for the given CA
- *
- * Handle a CA error interrupt.  Simply a wrapper around a SAL call which
- * defers processing to the SGI prom.
- */
-static irqreturn_t
-tioca_error_intr_handler(int irq, void *arg)
-{
-       struct tioca_common *soft = arg;
-       struct ia64_sal_retval ret_stuff;
-       u64 segment;
-       u64 busnum;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       segment = soft->ca_common.bs_persist_segment;
-       busnum = soft->ca_common.bs_persist_busnum;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
-                       segment, busnum, 0, 0, 0, 0, 0);
-
-       return IRQ_HANDLED;
-}
-
-/**
- * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus
- * @prom_bussoft: Common prom/kernel struct representing the bus
- *
- * Replicates the tioca_common pointed to by @prom_bussoft in kernel
- * space.  Allocates and initializes a kernel-only area for a given CA,
- * and sets up an irq for handling CA error interrupts.
- *
- * On successful setup, returns the kernel version of tioca_common back to
- * the caller.
- */
-static void *
-tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
-{
-       struct tioca_common *tioca_common;
-       struct tioca_kernel *tioca_kern;
-       struct pci_bus *bus;
-
-       /* sanity check prom rev */
-
-       if (is_shub1() && sn_sal_rev() < 0x0406) {
-               printk
-                   (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "
-                    "for tioca support\n", __func__);
-               return NULL;
-       }
-
-       /*
-        * Allocate kernel bus soft and copy from prom.
-        */
-
-       tioca_common = kmemdup(prom_bussoft, sizeof(struct tioca_common),
-                              GFP_KERNEL);
-       if (!tioca_common)
-               return NULL;
-
-       tioca_common->ca_common.bs_base = (unsigned long)
-               ioremap(REGION_OFFSET(tioca_common->ca_common.bs_base),
-                       sizeof(struct tioca_common));
-
-       /* init kernel-private area */
-
-       tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL);
-       if (!tioca_kern) {
-               kfree(tioca_common);
-               return NULL;
-       }
-
-       tioca_kern->ca_common = tioca_common;
-       spin_lock_init(&tioca_kern->ca_lock);
-       INIT_LIST_HEAD(&tioca_kern->ca_dmamaps);
-       tioca_kern->ca_closest_node =
-           nasid_to_cnodeid(tioca_common->ca_closest_nasid);
-       tioca_common->ca_kernel_private = (u64) tioca_kern;
-
-       bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment,
-               tioca_common->ca_common.bs_persist_busnum);
-       BUG_ON(!bus);
-       tioca_kern->ca_devices = &bus->devices;
-
-       /* init GART */
-
-       if (tioca_gart_init(tioca_kern) < 0) {
-               kfree(tioca_kern);
-               kfree(tioca_common);
-               return NULL;
-       }
-
-       tioca_gart_found++;
-       list_add(&tioca_kern->ca_list, &tioca_list);
-
-       if (request_irq(SGI_TIOCA_ERROR,
-                       tioca_error_intr_handler,
-                       IRQF_SHARED, "TIOCA error", (void *)tioca_common))
-               printk(KERN_WARNING
-                      "%s:  Unable to get irq %d.  "
-                      "Error interrupts won't be routed for TIOCA bus %d\n",
-                      __func__, SGI_TIOCA_ERROR,
-                      (int)tioca_common->ca_common.bs_persist_busnum);
-
-       irq_set_handler(SGI_TIOCA_ERROR, handle_level_irq);
-       sn_set_err_irq_affinity(SGI_TIOCA_ERROR);
-
-       /* Setup locality information */
-       controller->node = tioca_kern->ca_closest_node;
-       return tioca_common;
-}
-
-static struct sn_pcibus_provider tioca_pci_interfaces = {
-       .dma_map = tioca_dma_map,
-       .dma_map_consistent = tioca_dma_map,
-       .dma_unmap = tioca_dma_unmap,
-       .bus_fixup = tioca_bus_fixup,
-       .force_interrupt = NULL,
-       .target_interrupt = NULL
-};
-
-/**
- * tioca_init_provider - init SN PCI provider ops for TIO CA
- */
-int
-tioca_init_provider(void)
-{
-       sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces;
-       return 0;
-}
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
deleted file mode 100644 (file)
index 3bd9abc..0000000
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/tioce_provider.h>
-
-/*
- * 1/26/2006
- *
- * WAR for SGI PV 944642.  For revA TIOCE, need to use the following recipe
- * (taken from the above PV) before and after accessing tioce internal MMR's
- * to avoid tioce lockups.
- *
- * The recipe as taken from the PV:
- *
- *     if(mmr address < 0x45000) {
- *             if(mmr address == 0 or 0x80)
- *                     mmr wrt or read address 0xc0
- *             else if(mmr address == 0x148 or 0x200)
- *                     mmr wrt or read address 0x28
- *             else
- *                     mmr wrt or read address 0x158
- *
- *             do desired mmr access (rd or wrt)
- *
- *             if(mmr address == 0x100)
- *                     mmr wrt or read address 0x38
- *             mmr wrt or read address 0xb050
- *     } else
- *             do desired mmr access
- *
- * According to hw, we can use reads instead of writes to the above address
- *
- * Note this WAR can only to be used for accessing internal MMR's in the
- * TIOCE Coretalk Address Range 0x0 - 0x07ff_ffff.  This includes the
- * "Local CE Registers and Memories" and "PCI Compatible Config Space" address
- * spaces from table 2-1 of the "CE Programmer's Reference Overview" document.
- *
- * All registers defined in struct tioce will meet that criteria.
- */
-
-static inline void
-tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr)
-{
-       u64 mmr_base;
-       u64 mmr_offset;
-
-       if (kern->ce_common->ce_rev != TIOCE_REV_A)
-               return;
-
-       mmr_base = kern->ce_common->ce_pcibus.bs_base;
-       mmr_offset = (unsigned long)mmr_addr - mmr_base;
-
-       if (mmr_offset < 0x45000) {
-               u64 mmr_war_offset;
-
-               if (mmr_offset == 0 || mmr_offset == 0x80)
-                       mmr_war_offset = 0xc0;
-               else if (mmr_offset == 0x148 || mmr_offset == 0x200)
-                       mmr_war_offset = 0x28;
-               else
-                       mmr_war_offset = 0x158;
-
-               readq_relaxed((void __iomem *)(mmr_base + mmr_war_offset));
-       }
-}
-
-static inline void
-tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr)
-{
-       u64 mmr_base;
-       u64 mmr_offset;
-
-       if (kern->ce_common->ce_rev != TIOCE_REV_A)
-               return;
-
-       mmr_base = kern->ce_common->ce_pcibus.bs_base;
-       mmr_offset = (unsigned long)mmr_addr - mmr_base;
-
-       if (mmr_offset < 0x45000) {
-               if (mmr_offset == 0x100)
-                       readq_relaxed((void __iomem *)(mmr_base + 0x38));
-               readq_relaxed((void __iomem *)(mmr_base + 0xb050));
-       }
-}
-
-/* load mmr contents into a variable */
-#define tioce_mmr_load(kern, mmrp, varp) do {\
-       tioce_mmr_war_pre(kern, mmrp); \
-       *(varp) = readq_relaxed(mmrp); \
-       tioce_mmr_war_post(kern, mmrp); \
-} while (0)
-
-/* store variable contents into mmr */
-#define tioce_mmr_store(kern, mmrp, varp) do {\
-       tioce_mmr_war_pre(kern, mmrp); \
-       writeq(*varp, mmrp); \
-       tioce_mmr_war_post(kern, mmrp); \
-} while (0)
-
-/* store immediate value into mmr */
-#define tioce_mmr_storei(kern, mmrp, val) do {\
-       tioce_mmr_war_pre(kern, mmrp); \
-       writeq(val, mmrp); \
-       tioce_mmr_war_post(kern, mmrp); \
-} while (0)
-
-/* set bits (immediate value) into mmr */
-#define tioce_mmr_seti(kern, mmrp, bits) do {\
-       u64 tmp; \
-       tioce_mmr_load(kern, mmrp, &tmp); \
-       tmp |= (bits); \
-       tioce_mmr_store(kern, mmrp, &tmp); \
-} while (0)
-
-/* clear bits (immediate value) into mmr */
-#define tioce_mmr_clri(kern, mmrp, bits) do { \
-       u64 tmp; \
-       tioce_mmr_load(kern, mmrp, &tmp); \
-       tmp &= ~(bits); \
-       tioce_mmr_store(kern, mmrp, &tmp); \
-} while (0)
-
-/**
- * Bus address ranges for the 5 flavors of TIOCE DMA
- */
-
-#define TIOCE_D64_MIN  0x8000000000000000UL
-#define TIOCE_D64_MAX  0xffffffffffffffffUL
-#define TIOCE_D64_ADDR(a)      ((a) >= TIOCE_D64_MIN)
-
-#define TIOCE_D32_MIN  0x0000000080000000UL
-#define TIOCE_D32_MAX  0x00000000ffffffffUL
-#define TIOCE_D32_ADDR(a)      ((a) >= TIOCE_D32_MIN && (a) <= TIOCE_D32_MAX)
-
-#define TIOCE_M32_MIN  0x0000000000000000UL
-#define TIOCE_M32_MAX  0x000000007fffffffUL
-#define TIOCE_M32_ADDR(a)      ((a) >= TIOCE_M32_MIN && (a) <= TIOCE_M32_MAX)
-
-#define TIOCE_M40_MIN  0x0000004000000000UL
-#define TIOCE_M40_MAX  0x0000007fffffffffUL
-#define TIOCE_M40_ADDR(a)      ((a) >= TIOCE_M40_MIN && (a) <= TIOCE_M40_MAX)
-
-#define TIOCE_M40S_MIN 0x0000008000000000UL
-#define TIOCE_M40S_MAX 0x000000ffffffffffUL
-#define TIOCE_M40S_ADDR(a)     ((a) >= TIOCE_M40S_MIN && (a) <= TIOCE_M40S_MAX)
-
-/*
- * ATE manipulation macros.
- */
-
-#define ATE_PAGESHIFT(ps)      (__ffs(ps))
-#define ATE_PAGEMASK(ps)       ((ps)-1)
-
-#define ATE_PAGE(x, ps) ((x) >> ATE_PAGESHIFT(ps))
-#define ATE_NPAGES(start, len, pagesize) \
-       (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
-
-#define ATE_VALID(ate) ((ate) & (1UL << 63))
-#define ATE_MAKE(addr, ps, msi) \
-       (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0))
-
-/*
- * Flavors of ate-based mapping supported by tioce_alloc_map()
- */
-
-#define TIOCE_ATE_M32  1
-#define TIOCE_ATE_M40  2
-#define TIOCE_ATE_M40S 3
-
-#define KB(x)  ((u64)(x) << 10)
-#define MB(x)  ((u64)(x) << 20)
-#define GB(x)  ((u64)(x) << 30)
-
-/**
- * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode
- * @ct_addr: system coretalk address
- *
- * Map @ct_addr into 64-bit CE bus space.  No device context is necessary
- * and no CE mapping are consumed.
- *
- * Bits 53:0 come from the coretalk address.  The remaining bits are set as
- * follows:
- *
- * 63    - must be 1 to indicate d64 mode to CE hardware
- * 62    - barrier bit ... controlled with tioce_dma_barrier()
- * 61    - msi bit ... specified through dma_flags
- * 60:54 - reserved, MBZ
- */
-static u64
-tioce_dma_d64(unsigned long ct_addr, int dma_flags)
-{
-       u64 bus_addr;
-
-       bus_addr = ct_addr | (1UL << 63);
-       if (dma_flags & SN_DMA_MSI)
-               bus_addr |= (1UL << 61);
-
-       return bus_addr;
-}
-
-/**
- * pcidev_to_tioce - return misc ce related pointers given a pci_dev
- * @pci_dev: pci device context
- * @base: ptr to store struct tioce_mmr * for the CE holding this device
- * @kernel: ptr to store struct tioce_kernel * for the CE holding this device
- * @port: ptr to store the CE port number that this device is on
- *
- * Return pointers to various CE-related structures for the CE upstream of
- * @pci_dev.
- */
-static inline void
-pcidev_to_tioce(struct pci_dev *pdev, struct tioce __iomem **base,
-               struct tioce_kernel **kernel, int *port)
-{
-       struct pcidev_info *pcidev_info;
-       struct tioce_common *ce_common;
-       struct tioce_kernel *ce_kernel;
-
-       pcidev_info = SN_PCIDEV_INFO(pdev);
-       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
-       ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
-
-       if (base)
-               *base = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
-       if (kernel)
-               *kernel = ce_kernel;
-
-       /*
-        * we use port as a zero-based value internally, even though the
-        * documentation is 1-based.
-        */
-       if (port)
-               *port =
-                   (pdev->bus->number < ce_kernel->ce_port1_secondary) ? 0 : 1;
-}
-
-/**
- * tioce_alloc_map - Given a coretalk address, map it to pcie bus address
- * space using one of the various ATE-based address modes.
- * @ce_kern: tioce context
- * @type: map mode to use
- * @port: 0-based port that the requesting device is downstream of
- * @ct_addr: the coretalk address to map
- * @len: number of bytes to map
- *
- * Given the addressing type, set up various parameters that define the
- * ATE pool to use.  Search for a contiguous block of entries to cover the
- * length, and if enough resources exist, fill in the ATEs and construct a
- * tioce_dmamap struct to track the mapping.
- */
-static u64
-tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
-               u64 ct_addr, int len, int dma_flags)
-{
-       int i;
-       int j;
-       int first;
-       int last;
-       int entries;
-       int nates;
-       u64 pagesize;
-       int msi_capable, msi_wanted;
-       u64 *ate_shadow;
-       u64 __iomem *ate_reg;
-       u64 addr;
-       struct tioce __iomem *ce_mmr;
-       u64 bus_base;
-       struct tioce_dmamap *map;
-
-       ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
-
-       switch (type) {
-       case TIOCE_ATE_M32:
-               /*
-                * The first 64 entries of the ate3240 pool are dedicated to
-                * super-page (TIOCE_ATE_M40S) mode.
-                */
-               first = 64;
-               entries = TIOCE_NUM_M3240_ATES - 64;
-               ate_shadow = ce_kern->ce_ate3240_shadow;
-               ate_reg = ce_mmr->ce_ure_ate3240;
-               pagesize = ce_kern->ce_ate3240_pagesize;
-               bus_base = TIOCE_M32_MIN;
-               msi_capable = 1;
-               break;
-       case TIOCE_ATE_M40:
-               first = 0;
-               entries = TIOCE_NUM_M40_ATES;
-               ate_shadow = ce_kern->ce_ate40_shadow;
-               ate_reg = ce_mmr->ce_ure_ate40;
-               pagesize = MB(64);
-               bus_base = TIOCE_M40_MIN;
-               msi_capable = 0;
-               break;
-       case TIOCE_ATE_M40S:
-               /*
-                * ate3240 entries 0-31 are dedicated to port1 super-page
-                * mappings.  ate3240 entries 32-63 are dedicated to port2.
-                */
-               first = port * 32;
-               entries = 32;
-               ate_shadow = ce_kern->ce_ate3240_shadow;
-               ate_reg = ce_mmr->ce_ure_ate3240;
-               pagesize = GB(16);
-               bus_base = TIOCE_M40S_MIN;
-               msi_capable = 0;
-               break;
-       default:
-               return 0;
-       }
-
-       msi_wanted = dma_flags & SN_DMA_MSI;
-       if (msi_wanted && !msi_capable)
-               return 0;
-
-       nates = ATE_NPAGES(ct_addr, len, pagesize);
-       if (nates > entries)
-               return 0;
-
-       last = first + entries - nates;
-       for (i = first; i <= last; i++) {
-               if (ATE_VALID(ate_shadow[i]))
-                       continue;
-
-               for (j = i; j < i + nates; j++)
-                       if (ATE_VALID(ate_shadow[j]))
-                               break;
-
-               if (j >= i + nates)
-                       break;
-       }
-
-       if (i > last)
-               return 0;
-
-       map = kzalloc(sizeof(struct tioce_dmamap), GFP_ATOMIC);
-       if (!map)
-               return 0;
-
-       addr = ct_addr;
-       for (j = 0; j < nates; j++) {
-               u64 ate;
-
-               ate = ATE_MAKE(addr, pagesize, msi_wanted);
-               ate_shadow[i + j] = ate;
-               tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate);
-               addr += pagesize;
-       }
-
-       map->refcnt = 1;
-       map->nbytes = nates * pagesize;
-       map->ct_start = ct_addr & ~ATE_PAGEMASK(pagesize);
-       map->pci_start = bus_base + (i * pagesize);
-       map->ate_hw = &ate_reg[i];
-       map->ate_shadow = &ate_shadow[i];
-       map->ate_count = nates;
-
-       list_add(&map->ce_dmamap_list, &ce_kern->ce_dmamap_list);
-
-       return (map->pci_start + (ct_addr - map->ct_start));
-}
-
-/**
- * tioce_dma_d32 - create a DMA mapping using 32-bit direct mode
- * @pdev: linux pci_dev representing the function
- * @paddr: system physical address
- *
- * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
- */
-static u64
-tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags)
-{
-       int dma_ok;
-       int port;
-       struct tioce __iomem *ce_mmr;
-       struct tioce_kernel *ce_kern;
-       u64 ct_upper;
-       u64 ct_lower;
-       dma_addr_t bus_addr;
-
-       if (dma_flags & SN_DMA_MSI)
-               return 0;
-
-       ct_upper = ct_addr & ~0x3fffffffUL;
-       ct_lower = ct_addr & 0x3fffffffUL;
-
-       pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
-
-       if (ce_kern->ce_port[port].dirmap_refcnt == 0) {
-               u64 tmp;
-
-               ce_kern->ce_port[port].dirmap_shadow = ct_upper;
-               tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port],
-                                ct_upper);
-               tmp = ce_mmr->ce_ure_dir_map[port];
-               dma_ok = 1;
-       } else
-               dma_ok = (ce_kern->ce_port[port].dirmap_shadow == ct_upper);
-
-       if (dma_ok) {
-               ce_kern->ce_port[port].dirmap_refcnt++;
-               bus_addr = TIOCE_D32_MIN + ct_lower;
-       } else
-               bus_addr = 0;
-
-       return bus_addr;
-}
-
-/**
- * tioce_dma_barrier - swizzle a TIOCE bus address to include or exclude
- * the barrier bit.
- * @bus_addr:  bus address to swizzle
- *
- * Given a TIOCE bus address, set the appropriate bit to indicate barrier
- * attributes.
- */
-static u64
-tioce_dma_barrier(u64 bus_addr, int on)
-{
-       u64 barrier_bit;
-
-       /* barrier not supported in M40/M40S mode */
-       if (TIOCE_M40_ADDR(bus_addr) || TIOCE_M40S_ADDR(bus_addr))
-               return bus_addr;
-
-       if (TIOCE_D64_ADDR(bus_addr))
-               barrier_bit = (1UL << 62);
-       else                    /* must be m32 or d32 */
-               barrier_bit = (1UL << 30);
-
-       return (on) ? (bus_addr | barrier_bit) : (bus_addr & ~barrier_bit);
-}
-
-/**
- * tioce_dma_unmap - release CE mapping resources
- * @pdev: linux pci_dev representing the function
- * @bus_addr: bus address returned by an earlier tioce_dma_map
- * @dir: mapping direction (unused)
- *
- * Locate mapping resources associated with @bus_addr and release them.
- * For mappings created using the direct modes there are no resources
- * to release.
- */
-void
-tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
-{
-       int i;
-       int port;
-       struct tioce_kernel *ce_kern;
-       struct tioce __iomem *ce_mmr;
-       unsigned long flags;
-
-       bus_addr = tioce_dma_barrier(bus_addr, 0);
-       pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
-
-       /* nothing to do for D64 */
-
-       if (TIOCE_D64_ADDR(bus_addr))
-               return;
-
-       spin_lock_irqsave(&ce_kern->ce_lock, flags);
-
-       if (TIOCE_D32_ADDR(bus_addr)) {
-               if (--ce_kern->ce_port[port].dirmap_refcnt == 0) {
-                       ce_kern->ce_port[port].dirmap_shadow = 0;
-                       tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_dir_map[port],
-                                        0);
-               }
-       } else {
-               struct tioce_dmamap *map;
-
-               list_for_each_entry(map, &ce_kern->ce_dmamap_list,
-                                   ce_dmamap_list) {
-                       u64 last;
-
-                       last = map->pci_start + map->nbytes - 1;
-                       if (bus_addr >= map->pci_start && bus_addr <= last)
-                               break;
-               }
-
-               if (&map->ce_dmamap_list == &ce_kern->ce_dmamap_list) {
-                       printk(KERN_WARNING
-                              "%s:  %s - no map found for bus_addr 0x%llx\n",
-                              __func__, pci_name(pdev), bus_addr);
-               } else if (--map->refcnt == 0) {
-                       for (i = 0; i < map->ate_count; i++) {
-                               map->ate_shadow[i] = 0;
-                               tioce_mmr_storei(ce_kern, &map->ate_hw[i], 0);
-                       }
-
-                       list_del(&map->ce_dmamap_list);
-                       kfree(map);
-               }
-       }
-
-       spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
-}
-
-/**
- * tioce_do_dma_map - map pages for PCI DMA
- * @pdev: linux pci_dev representing the function
- * @paddr: host physical address to map
- * @byte_count: bytes to map
- *
- * This is the main wrapper for mapping host physical pages to CE PCI space.
- * The mapping mode used is based on the device's dma_mask.
- */
-static u64
-tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
-                int barrier, int dma_flags)
-{
-       unsigned long flags;
-       u64 ct_addr;
-       u64 mapaddr = 0;
-       struct tioce_kernel *ce_kern;
-       struct tioce_dmamap *map;
-       int port;
-       u64 dma_mask;
-
-       dma_mask = (barrier) ? pdev->dev.coherent_dma_mask : pdev->dma_mask;
-
-       /* cards must be able to address at least 31 bits */
-       if (dma_mask < 0x7fffffffUL)
-               return 0;
-
-       if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
-               ct_addr = PHYS_TO_TIODMA(paddr);
-       else
-               ct_addr = paddr;
-
-       /*
-        * If the device can generate 64 bit addresses, create a D64 map.
-        */
-       if (dma_mask == ~0UL) {
-               mapaddr = tioce_dma_d64(ct_addr, dma_flags);
-               if (mapaddr)
-                       goto dma_map_done;
-       }
-
-       pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
-
-       spin_lock_irqsave(&ce_kern->ce_lock, flags);
-
-       /*
-        * D64 didn't work ... See if we have an existing map that covers
-        * this address range.  Must account for devices dma_mask here since
-        * an existing map might have been done in a mode using more pci
-        * address bits than this device can support.
-        */
-       list_for_each_entry(map, &ce_kern->ce_dmamap_list, ce_dmamap_list) {
-               u64 last;
-
-               last = map->ct_start + map->nbytes - 1;
-               if (ct_addr >= map->ct_start &&
-                   ct_addr + byte_count - 1 <= last &&
-                   map->pci_start <= dma_mask) {
-                       map->refcnt++;
-                       mapaddr = map->pci_start + (ct_addr - map->ct_start);
-                       break;
-               }
-       }
-
-       /*
-        * If we don't have a map yet, and the card can generate 40
-        * bit addresses, try the M40/M40S modes.  Note these modes do not
-        * support a barrier bit, so if we need a consistent map these
-        * won't work.
-        */
-       if (!mapaddr && !barrier && dma_mask >= 0xffffffffffUL) {
-               /*
-                * We have two options for 40-bit mappings:  16GB "super" ATEs
-                * and 64MB "regular" ATEs.  We'll try both if needed for a
-                * given mapping but which one we try first depends on the
-                * size.  For requests >64MB, prefer to use a super page with
-                * regular as the fallback. Otherwise, try in the reverse order.
-                */
-
-               if (byte_count > MB(64)) {
-                       mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
-                                                 port, ct_addr, byte_count,
-                                                 dma_flags);
-                       if (!mapaddr)
-                               mapaddr =
-                                   tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
-                                                   ct_addr, byte_count,
-                                                   dma_flags);
-               } else {
-                       mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
-                                                 ct_addr, byte_count,
-                                                 dma_flags);
-                       if (!mapaddr)
-                               mapaddr =
-                                   tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
-                                                   port, ct_addr, byte_count,
-                                                   dma_flags);
-               }
-       }
-
-       /*
-        * 32-bit direct is the next mode to try
-        */
-       if (!mapaddr && dma_mask >= 0xffffffffUL)
-               mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags);
-
-       /*
-        * Last resort, try 32-bit ATE-based map.
-        */
-       if (!mapaddr)
-               mapaddr =
-                   tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
-                                   byte_count, dma_flags);
-
-       spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
-
-dma_map_done:
-       if (mapaddr && barrier)
-               mapaddr = tioce_dma_barrier(mapaddr, 1);
-
-       return mapaddr;
-}
-
-/**
- * tioce_dma - standard pci dma map interface
- * @pdev: pci device requesting the map
- * @paddr: system physical address to map into pci space
- * @byte_count: # bytes to map
- *
- * Simply call tioce_do_dma_map() to create a map with the barrier bit clear
- * in the address.
- */
-static u64
-tioce_dma(struct pci_dev *pdev, unsigned long  paddr, size_t byte_count, int dma_flags)
-{
-       return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags);
-}
-
-/**
- * tioce_dma_consistent - consistent pci dma map interface
- * @pdev: pci device requesting the map
- * @paddr: system physical address to map into pci space
- * @byte_count: # bytes to map
- *
- * Simply call tioce_do_dma_map() to create a map with the barrier bit set
- * in the address.
- */
-static u64
-tioce_dma_consistent(struct pci_dev *pdev, unsigned long  paddr, size_t byte_count, int dma_flags)
-{
-       return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags);
-}
-
-/**
- * tioce_error_intr_handler - SGI TIO CE error interrupt handler
- * @irq: unused
- * @arg: pointer to tioce_common struct for the given CE
- *
- * Handle a CE error interrupt.  Simply a wrapper around a SAL call which
- * defers processing to the SGI prom.
- */
-static irqreturn_t
-tioce_error_intr_handler(int irq, void *arg)
-{
-       struct tioce_common *soft = arg;
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
-                       soft->ce_pcibus.bs_persist_segment,
-                       soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0);
-
-       if (ret_stuff.v0)
-               panic("tioce_error_intr_handler:  Fatal TIOCE error");
-
-       return IRQ_HANDLED;
-}
-
-/**
- * tioce_reserve_m32 - reserve M32 ATEs for the indicated address range
- * @tioce_kernel: TIOCE context to reserve ATEs for
- * @base: starting bus address to reserve
- * @limit: last bus address to reserve
- *
- * If base/limit falls within the range of bus space mapped through the
- * M32 space, reserve the resources corresponding to the range.
- */
-static void
-tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit)
-{
-       int ate_index, last_ate, ps;
-       struct tioce __iomem *ce_mmr;
-
-       ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
-       ps = ce_kern->ce_ate3240_pagesize;
-       ate_index = ATE_PAGE(base, ps);
-       last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1;
-
-       if (ate_index < 64)
-               ate_index = 64;
-
-       if (last_ate >= TIOCE_NUM_M3240_ATES)
-               last_ate = TIOCE_NUM_M3240_ATES - 1;
-
-       while (ate_index <= last_ate) {
-               u64 ate;
-
-               ate = ATE_MAKE(0xdeadbeef, ps, 0);
-               ce_kern->ce_ate3240_shadow[ate_index] = ate;
-               tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index],
-                                ate);
-               ate_index++;
-       }
-}
-
-/**
- * tioce_kern_init - init kernel structures related to a given TIOCE
- * @tioce_common: ptr to a cached tioce_common struct that originated in prom
- */
-static struct tioce_kernel *
-tioce_kern_init(struct tioce_common *tioce_common)
-{
-       int i;
-       int ps;
-       int dev;
-       u32 tmp;
-       unsigned int seg, bus;
-       struct tioce __iomem *tioce_mmr;
-       struct tioce_kernel *tioce_kern;
-
-       tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL);
-       if (!tioce_kern) {
-               return NULL;
-       }
-
-       tioce_kern->ce_common = tioce_common;
-       spin_lock_init(&tioce_kern->ce_lock);
-       INIT_LIST_HEAD(&tioce_kern->ce_dmamap_list);
-       tioce_common->ce_kernel_private = (u64) tioce_kern;
-
-       /*
-        * Determine the secondary bus number of the port2 logical PPB.
-        * This is used to decide whether a given pci device resides on
-        * port1 or port2.  Note:  We don't have enough plumbing set up
-        * here to use pci_read_config_xxx() so use raw_pci_read().
-        */
-
-       seg = tioce_common->ce_pcibus.bs_persist_segment;
-       bus = tioce_common->ce_pcibus.bs_persist_busnum;
-
-       raw_pci_read(seg, bus, PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1,&tmp);
-       tioce_kern->ce_port1_secondary = (u8) tmp;
-
-       /*
-        * Set PMU pagesize to the largest size available, and zero out
-        * the ATEs.
-        */
-
-       tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
-       tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map,
-                      CE_URE_PAGESIZE_MASK);
-       tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map,
-                      CE_URE_256K_PAGESIZE);
-       ps = tioce_kern->ce_ate3240_pagesize = KB(256);
-
-       for (i = 0; i < TIOCE_NUM_M40_ATES; i++) {
-               tioce_kern->ce_ate40_shadow[i] = 0;
-               tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate40[i], 0);
-       }
-
-       for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) {
-               tioce_kern->ce_ate3240_shadow[i] = 0;
-               tioce_mmr_storei(tioce_kern, &tioce_mmr->ce_ure_ate3240[i], 0);
-       }
-
-       /*
-        * Reserve ATEs corresponding to reserved address ranges.  These
-        * include:
-        *
-        *      Memory space covered by each PPB mem base/limit register
-        *      Memory space covered by each PPB prefetch base/limit register
-        *
-        * These bus ranges are for pio (downstream) traffic only, and so
-        * cannot be used for DMA.
-        */
-
-       for (dev = 1; dev <= 2; dev++) {
-               u64 base, limit;
-
-               /* mem base/limit */
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_MEMORY_BASE, 2, &tmp);
-               base = (u64)tmp << 16;
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_MEMORY_LIMIT, 2, &tmp);
-               limit = (u64)tmp << 16;
-               limit |= 0xfffffUL;
-
-               if (base < limit)
-                       tioce_reserve_m32(tioce_kern, base, limit);
-
-               /*
-                * prefetch mem base/limit.  The tioce ppb's have 64-bit
-                * decoders, so read the upper portions w/o checking the
-                * attributes.
-                */
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_PREF_MEMORY_BASE, 2, &tmp);
-               base = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16;
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_PREF_BASE_UPPER32, 4, &tmp);
-               base |= (u64)tmp << 32;
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_PREF_MEMORY_LIMIT, 2, &tmp);
-
-               limit = ((u64)tmp & PCI_PREF_RANGE_MASK) << 16;
-               limit |= 0xfffffUL;
-
-               raw_pci_read(seg, bus, PCI_DEVFN(dev, 0),
-                                 PCI_PREF_LIMIT_UPPER32, 4, &tmp);
-               limit |= (u64)tmp << 32;
-
-               if ((base < limit) && TIOCE_M32_ADDR(base))
-                       tioce_reserve_m32(tioce_kern, base, limit);
-       }
-
-       return tioce_kern;
-}
-
-/**
- * tioce_force_interrupt - implement altix force_interrupt() backend for CE
- * @sn_irq_info: sn asic irq that we need an interrupt generated for
- *
- * Given an sn_irq_info struct, set the proper bit in ce_adm_force_int to
- * force a secondary interrupt to be generated.  This is to work around an
- * asic issue where there is a small window of opportunity for a legacy device
- * interrupt to be lost.
- */
-static void
-tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
-{
-       struct pcidev_info *pcidev_info;
-       struct tioce_common *ce_common;
-       struct tioce_kernel *ce_kern;
-       struct tioce __iomem *ce_mmr;
-       u64 force_int_val;
-
-       if (!sn_irq_info->irq_bridge)
-               return;
-
-       if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_TIOCE)
-               return;
-
-       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       if (!pcidev_info)
-               return;
-
-       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
-       ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
-       ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
-
-       /*
-        * TIOCE Rev A workaround (PV 945826), force an interrupt by writing
-        * the TIO_INTx register directly (1/26/2006)
-        */
-       if (ce_common->ce_rev == TIOCE_REV_A) {
-               u64 int_bit_mask = (1ULL << sn_irq_info->irq_int_bit);
-               u64 status;
-
-               tioce_mmr_load(ce_kern, &ce_mmr->ce_adm_int_status, &status);
-               if (status & int_bit_mask) {
-                       u64 force_irq = (1 << 8) | sn_irq_info->irq_irq;
-                       u64 ctalk = sn_irq_info->irq_xtalkaddr;
-                       u64 nasid, offset;
-
-                       nasid = (ctalk & CTALK_NASID_MASK) >> CTALK_NASID_SHFT;
-                       offset = (ctalk & CTALK_NODE_OFFSET);
-                       HUB_S(TIO_IOSPACE_ADDR(nasid, offset), force_irq);
-               }
-
-               return;
-       }
-
-       /*
-        * irq_int_bit is originally set up by prom, and holds the interrupt
-        * bit shift (not mask) as defined by the bit definitions in the
-        * ce_adm_int mmr.  These shifts are not the same for the
-        * ce_adm_force_int register, so do an explicit mapping here to make
-        * things clearer.
-        */
-
-       switch (sn_irq_info->irq_int_bit) {
-       case CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT;
-               break;
-       case CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT:
-               force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT;
-               break;
-       default:
-               return;
-       }
-       tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_force_int, force_int_val);
-}
-
-/**
- * tioce_target_interrupt - implement set_irq_affinity for tioce resident
- * functions.  Note:  only applies to line interrupts, not MSI's.
- *
- * @sn_irq_info: SN IRQ context
- *
- * Given an sn_irq_info, set the associated CE device's interrupt destination
- * register.  Since the interrupt destination registers are on a per-ce-slot
- * basis, this will retarget line interrupts for all functions downstream of
- * the slot.
- */
-static void
-tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
-{
-       struct pcidev_info *pcidev_info;
-       struct tioce_common *ce_common;
-       struct tioce_kernel *ce_kern;
-       struct tioce __iomem *ce_mmr;
-       int bit;
-       u64 vector;
-
-       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
-       if (!pcidev_info)
-               return;
-
-       ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
-       ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
-       ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
-
-       bit = sn_irq_info->irq_int_bit;
-
-       tioce_mmr_seti(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit));
-       vector = (u64)sn_irq_info->irq_irq << INTR_VECTOR_SHFT;
-       vector |= sn_irq_info->irq_xtalkaddr;
-       tioce_mmr_storei(ce_kern, &ce_mmr->ce_adm_int_dest[bit], vector);
-       tioce_mmr_clri(ce_kern, &ce_mmr->ce_adm_int_mask, (1UL << bit));
-
-       tioce_force_interrupt(sn_irq_info);
-}
-
-/**
- * tioce_bus_fixup - perform final PCI fixup for a TIO CE bus
- * @prom_bussoft: Common prom/kernel struct representing the bus
- *
- * Replicates the tioce_common pointed to by @prom_bussoft in kernel
- * space.  Allocates and initializes a kernel-only area for a given CE,
- * and sets up an irq for handling CE error interrupts.
- *
- * On successful setup, returns the kernel version of tioce_common back to
- * the caller.
- */
-static void *
-tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
-{
-       struct tioce_common *tioce_common;
-       struct tioce_kernel *tioce_kern;
-       struct tioce __iomem *tioce_mmr;
-
-       /*
-        * Allocate kernel bus soft and copy from prom.
-        */
-
-       tioce_common = kzalloc(sizeof(struct tioce_common), GFP_KERNEL);
-       if (!tioce_common)
-               return NULL;
-
-       memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common));
-       tioce_common->ce_pcibus.bs_base = (unsigned long)
-               ioremap(REGION_OFFSET(tioce_common->ce_pcibus.bs_base),
-                       sizeof(struct tioce_common));
-
-       tioce_kern = tioce_kern_init(tioce_common);
-       if (tioce_kern == NULL) {
-               kfree(tioce_common);
-               return NULL;
-       }
-
-       /*
-        * Clear out any transient errors before registering the error
-        * interrupt handler.
-        */
-
-       tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
-       tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL);
-       tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias,
-                      ~0ULL);
-       tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_dre_comp_err_addr, 0ULL);
-
-       if (request_irq(SGI_PCIASIC_ERROR,
-                       tioce_error_intr_handler,
-                       IRQF_SHARED, "TIOCE error", (void *)tioce_common))
-               printk(KERN_WARNING
-                      "%s:  Unable to get irq %d.  "
-                      "Error interrupts won't be routed for "
-                      "TIOCE bus %04x:%02x\n",
-                      __func__, SGI_PCIASIC_ERROR,
-                      tioce_common->ce_pcibus.bs_persist_segment,
-                      tioce_common->ce_pcibus.bs_persist_busnum);
-
-       irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
-       sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
-       return tioce_common;
-}
-
-static struct sn_pcibus_provider tioce_pci_interfaces = {
-       .dma_map = tioce_dma,
-       .dma_map_consistent = tioce_dma_consistent,
-       .dma_unmap = tioce_dma_unmap,
-       .bus_fixup = tioce_bus_fixup,
-       .force_interrupt = tioce_force_interrupt,
-       .target_interrupt = tioce_target_interrupt
-};
-
-/**
- * tioce_init_provider - init SN PCI provider ops for TIO CE
- */
-int
-tioce_init_provider(void)
-{
-       sn_pci_provider[PCIIO_ASIC_TYPE_TIOCE] = &tioce_pci_interfaces;
-       return 0;
-}
index 124e441..2971965 100644 (file)
@@ -10,4 +10,3 @@
 ccflags-y := -Iarch/ia64/sn/include
 
 obj-y                          += setup.o
-obj-$(CONFIG_IA64_GENERIC)      += machvec.o
diff --git a/arch/ia64/uv/kernel/machvec.c b/arch/ia64/uv/kernel/machvec.c
deleted file mode 100644 (file)
index 50737a9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#define MACHVEC_PLATFORM_NAME  uv
-#define MACHVEC_PLATFORM_HEADER        <asm/machvec_uv.h>
-#include <asm/machvec_init.h>
index f149065..bb02548 100644 (file)
@@ -8,25 +8,20 @@
  * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
  */
 
+#include <linux/acpi.h>
+#include <linux/efi.h>
 #include <linux/module.h>
 #include <linux/percpu.h>
-#include <asm/sn/simulator.h>
+#include <asm/uv/uv.h>
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
 
+bool ia64_is_uv;
+EXPORT_SYMBOL_GPL(ia64_is_uv);
+
 DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info);
 
-#ifdef CONFIG_IA64_SGI_UV
-int sn_prom_type;
-long sn_partition_id;
-EXPORT_SYMBOL(sn_partition_id);
-long sn_coherency_id;
-EXPORT_SYMBOL_GPL(sn_coherency_id);
-long sn_region_size;
-EXPORT_SYMBOL(sn_region_size);
-#endif
-
 struct redir_addr {
        unsigned long redirect;
        unsigned long alias;
@@ -58,6 +53,34 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
        BUG();
 }
 
+void __init uv_probe_system_type(void)
+{
+       struct acpi_table_rsdp *rsdp;
+       struct acpi_table_xsdt *xsdt;
+
+       if (efi.acpi20 == EFI_INVALID_TABLE_ADDR) {
+               pr_err("ACPI 2.0 RSDP not found.\n");
+               return;
+       }
+
+       rsdp = (struct acpi_table_rsdp *)__va(efi.acpi20);
+       if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
+               pr_err("ACPI 2.0 RSDP signature incorrect.\n");
+               return;
+       }
+
+       xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
+       if (strncmp(xsdt->header.signature, ACPI_SIG_XSDT,
+                       sizeof(ACPI_SIG_XSDT) - 1)) {
+               pr_err("ACPI 2.0 XSDT signature incorrect.\n");
+               return;
+       }
+
+       if (!strcmp(xsdt->header.oem_id, "SGI") &&
+           !strcmp(xsdt->header.oem_table_id + 4, "UV"))
+               ia64_is_uv = true;
+}
+
 void __init uv_setup(char **cmdline_p)
 {
        union uvh_si_addr_map_config_u m_n_config;
@@ -66,30 +89,11 @@ void __init uv_setup(char **cmdline_p)
        int nid, cpu, m_val, n_val;
        unsigned long mmr_base, lowmem_redir_base, lowmem_redir_size;
 
-       if (IS_MEDUSA()) {
-               lowmem_redir_base = 0;
-               lowmem_redir_size = 0;
-               node_id.v = 0;
-               m_n_config.s.m_skt = 37;
-               m_n_config.s.n_skt = 0;
-               mmr_base = 0;
-#if 0
-               /* Need BIOS calls - TDB */
-               if (!ia64_sn_is_fake_prom())
-                       sn_prom_type = 1;
-               else
-#endif
-                       sn_prom_type = 2;
-               printk(KERN_INFO "Running on medusa with %s PROM\n",
-                                       (sn_prom_type == 1) ? "real" : "fake");
-       } else {
-               get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
-               node_id.v = uv_read_local_mmr(UVH_NODE_ID);
-               m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
-               mmr_base =
-                       uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
-                               ~UV_MMR_ENABLE;
-       }
+       get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
+       node_id.v = uv_read_local_mmr(UVH_NODE_ID);
+       m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
+       mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
+                       ~UV_MMR_ENABLE;
 
        m_val = m_n_config.s.m_skt;
        n_val = m_n_config.s.n_skt;
index 902255e..73bf5ea 100644 (file)
@@ -246,9 +246,9 @@ void __init config_atari(void)
        } else if (hwreg_present(tt_palette)) {
                ATARIHW_SET(TT_SHIFTER);
                pr_cont(" TT_SHIFTER");
-       } else if (hwreg_present(&shifter.bas_hi)) {
-               if (hwreg_present(&shifter.bas_lo) &&
-                   (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+       } else if (hwreg_present(&shifter_st.bas_hi)) {
+               if (hwreg_present(&shifter_st.bas_lo) &&
+                   (shifter_st.bas_lo = 0x0aau, shifter_st.bas_lo == 0x0aau)) {
                        ATARIHW_SET(EXTD_SHIFTER);
                        pr_cont(" EXTD_SHIFTER");
                } else {
index 04e0f21..9a33c1c 100644 (file)
@@ -125,6 +125,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -250,9 +251,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -330,7 +333,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -450,7 +452,6 @@ CONFIG_RTC_DRV_RP5C01=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -573,6 +574,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -582,8 +584,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -618,6 +622,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -636,6 +641,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -644,4 +650,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index c6abbb5..7fdbc79 100644 (file)
@@ -121,6 +121,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -246,9 +247,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -315,7 +318,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -410,7 +412,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -533,6 +534,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -542,8 +544,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -578,6 +582,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -596,6 +601,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -604,4 +610,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 06ae65b..f176340 100644 (file)
@@ -128,6 +128,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -253,9 +254,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -330,7 +333,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -432,7 +434,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -555,6 +556,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -564,8 +566,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -600,6 +604,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -618,6 +623,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -626,4 +632,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 5616b94..91154d6 100644 (file)
@@ -118,6 +118,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -243,9 +244,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -312,7 +315,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -403,7 +405,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -526,6 +527,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -535,8 +537,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -571,6 +575,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -589,6 +594,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -597,4 +603,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 1106521..c398c4a 100644 (file)
@@ -120,6 +120,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -245,9 +246,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -314,7 +317,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -412,7 +414,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -535,6 +536,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -544,8 +546,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -580,6 +584,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -598,6 +603,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -606,4 +612,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 226c6c0..350d004 100644 (file)
@@ -119,6 +119,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -244,9 +245,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -321,7 +324,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -434,7 +436,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -557,6 +558,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -566,8 +568,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -602,6 +606,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -620,6 +625,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -628,4 +634,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 39f6034..b838dd8 100644 (file)
@@ -139,6 +139,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -264,9 +265,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -354,7 +357,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -516,7 +518,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -639,6 +640,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -648,8 +650,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -684,6 +688,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -702,6 +707,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -710,4 +716,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 175a607..3f8dd61 100644 (file)
@@ -117,6 +117,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -242,9 +243,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -311,7 +314,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -402,7 +404,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -525,6 +526,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -534,8 +536,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -570,6 +574,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -588,6 +593,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -596,4 +602,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index f41c34d..ae3b2d4 100644 (file)
@@ -118,6 +118,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -243,9 +244,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -312,7 +315,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -403,7 +405,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -526,6 +527,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -535,8 +537,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -571,6 +575,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -589,6 +594,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -597,4 +603,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index c9d2cb0..cd61ef1 100644 (file)
@@ -119,6 +119,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -244,9 +245,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -320,7 +323,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -421,7 +423,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -544,6 +545,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -553,8 +555,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -589,6 +593,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -607,6 +612,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -615,4 +621,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 79a64fd..151f537 100644 (file)
@@ -115,6 +115,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -240,9 +241,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -309,7 +312,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -405,7 +407,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -528,6 +529,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -537,8 +539,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -573,6 +577,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -591,6 +596,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -599,3 +605,4 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
index e3402a5..1dcb0ee 100644 (file)
@@ -115,6 +115,7 @@ CONFIG_NFT_XFRM=m
 CONFIG_NFT_SOCKET=m
 CONFIG_NFT_OSF=m
 CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NFT_FIB_NETDEV=m
@@ -240,9 +241,11 @@ CONFIG_IP6_NF_RAW=m
 CONFIG_IP6_NF_NAT=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
-CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
 CONFIG_NFT_BRIDGE_REJECT=m
 CONFIG_NF_LOG_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
@@ -309,7 +312,6 @@ CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -404,7 +406,6 @@ CONFIG_RTC_DRV_GENERIC=m
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_DAX=m
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT4_FS=y
 CONFIG_REISERFS_FS=m
 CONFIG_JFS_FS=m
@@ -527,6 +528,7 @@ CONFIG_CRYPTO_KEYWRAP=m
 CONFIG_CRYPTO_ADIANTUM=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_XXHASH=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
@@ -536,8 +538,10 @@ CONFIG_CRYPTO_SHA3=m
 CONFIG_CRYPTO_SM3=m
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_CAST5=m
@@ -572,6 +576,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_WW_MUTEX_SELFTEST=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_SORT=m
+CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
 CONFIG_TEST_HEXDUMP=m
@@ -590,6 +595,7 @@ CONFIG_TEST_IDA=m
 CONFIG_TEST_VMALLOC=m
 CONFIG_TEST_USER_COPY=m
 CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
@@ -598,4 +604,5 @@ CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
 CONFIG_TEST_MEMCAT_P=m
 CONFIG_TEST_STACKINIT=m
+CONFIG_TEST_MEMINIT=m
 CONFIG_EARLY_PRINTK=y
index 5330082..9a038a3 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/types.h>
 #include <asm/bootinfo-atari.h>
-#include <asm/raw_io.h>
 #include <asm/kmap.h>
 
 extern u_long atari_mch_cookie;
@@ -132,14 +131,6 @@ extern struct atari_hw_present atari_hw_present;
  */
 
 
-#define atari_readb   raw_inb
-#define atari_writeb  raw_outb
-
-#define atari_inb_p   raw_inb
-#define atari_outb_p  raw_outb
-
-
-
 #include <linux/mm.h>
 #include <asm/cacheflush.h>
 
@@ -170,7 +161,7 @@ static inline void dma_cache_maintenance( unsigned long paddr,
 #define TT_HIGH 6
 
 #define SHF_BAS (0xffff8200)
-struct SHIFTER
+struct SHIFTER_ST
  {
        u_char pad1;
        u_char bas_hi;
@@ -187,7 +178,7 @@ struct SHIFTER
        u_char pad7;
        u_char bas_lo;
  };
-# define shifter ((*(volatile struct SHIFTER *)SHF_BAS))
+# define shifter_st ((*(volatile struct SHIFTER_ST *)SHF_BAS))
 
 #define SHF_FBAS (0xffff820e)
 struct SHIFTER_F030
index 6c03ca5..819f611 100644 (file)
 #include <asm-generic/iomap.h>
 
 #ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
+#define atari_readb   raw_inb
+#define atari_writeb  raw_outb
+
+#define atari_inb_p   raw_inb
+#define atari_outb_p  raw_outb
 #endif
 
 
index aac7f04..421b6c9 100644 (file)
@@ -28,14 +28,8 @@ static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size)
        return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
 }
 
-#define ioremap_nocache ioremap_nocache
-static inline void __iomem *ioremap_nocache(unsigned long physaddr,
-                                           unsigned long size)
-{
-       return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
-}
-
-#define ioremap_uc ioremap_nocache
+#define ioremap_nocache ioremap
+#define ioremap_uc ioremap
 #define ioremap_wt ioremap_wt
 static inline void __iomem *ioremap_wt(unsigned long physaddr,
                                       unsigned long size)
@@ -43,13 +37,6 @@ static inline void __iomem *ioremap_wt(unsigned long physaddr,
        return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
 }
 
-#define ioremap_fullcache ioremap_fullcache
-static inline void __iomem *ioremap_fullcache(unsigned long physaddr,
-                                             unsigned long size)
-{
-       return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
-}
-
 #define memset_io memset_io
 static inline void memset_io(volatile void __iomem *addr, unsigned char val,
                             int count)
index d9a08be..8a43bab 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo-mac.h>
 
@@ -82,11 +83,11 @@ struct mac_model
 #define MAC_EXP_PDS_NUBUS      3 /* Accepts PDS card and/or NuBus card(s) */
 #define MAC_EXP_PDS_COMM       4 /* Accepts PDS card or Comm Slot card */
 
-#define MAC_FLOPPY_IWM         0
-#define MAC_FLOPPY_SWIM_ADDR1  1
-#define MAC_FLOPPY_SWIM_ADDR2  2
-#define MAC_FLOPPY_SWIM_IOP    3
-#define MAC_FLOPPY_AV          4
+#define MAC_FLOPPY_UNSUPPORTED 0
+#define MAC_FLOPPY_SWIM_IOP    1
+#define MAC_FLOPPY_OLD         2
+#define MAC_FLOPPY_QUADRA      3
+#define MAC_FLOPPY_LC          4
 
 extern struct mac_model *macintosh_config;
 
index 205ac75..611f73b 100644 (file)
@@ -209,7 +209,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_IWM,
+               .floppy_type    = MAC_FLOPPY_UNSUPPORTED, /* IWM */
        },
 
        /*
@@ -224,7 +224,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_IWM,
+               .floppy_type    = MAC_FLOPPY_UNSUPPORTED, /* IWM */
        }, {
                .ident          = MAC_MODEL_IIX,
                .name           = "IIx",
@@ -233,7 +233,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_IICX,
                .name           = "IIcx",
@@ -242,7 +242,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_SE30,
                .name           = "SE/30",
@@ -251,7 +251,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        },
 
        /*
@@ -269,7 +269,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_IIFX,
                .name           = "IIfx",
@@ -278,7 +278,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_IIFX,
                .scc_type       = MAC_SCC_IOP,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_IOP,
+               .floppy_type    = MAC_FLOPPY_SWIM_IOP, /* SWIM */
        }, {
                .ident          = MAC_MODEL_IISI,
                .name           = "IIsi",
@@ -287,7 +287,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_IIVI,
                .name           = "IIvi",
@@ -296,7 +296,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        }, {
                .ident          = MAC_MODEL_IIVX,
                .name           = "IIvx",
@@ -305,7 +305,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        },
 
        /*
@@ -319,7 +319,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_IICI,
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        }, {
                .ident          = MAC_MODEL_CCL,
                .name           = "Color Classic",
@@ -328,7 +328,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_CCLII,
                .name           = "Color Classic II",
@@ -337,7 +337,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        },
 
        /*
@@ -352,7 +352,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        }, {
                .ident          = MAC_MODEL_LCII,
                .name           = "LC II",
@@ -361,7 +361,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        }, {
                .ident          = MAC_MODEL_LCIII,
                .name           = "LC III",
@@ -370,7 +370,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        },
 
        /*
@@ -391,7 +391,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_QUADRA,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_Q605_ACC,
                .name           = "Quadra 605",
@@ -400,7 +400,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_QUADRA,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_Q610,
                .name           = "Quadra 610",
@@ -410,7 +410,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_Q630,
                .name           = "Quadra 630",
@@ -420,7 +420,7 @@ static struct mac_model mac_data_table[] = {
                .ide_type       = MAC_IDE_QUADRA,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_PDS_COMM,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_Q650,
                .name           = "Quadra 650",
@@ -430,7 +430,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        },
        /* The Q700 does have a NS Sonic */
        {
@@ -442,7 +442,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM */
        }, {
                .ident          = MAC_MODEL_Q800,
                .name           = "Quadra 800",
@@ -452,7 +452,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_Q840,
                .name           = "Quadra 840AV",
@@ -462,7 +462,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_PSC,
                .ether_type     = MAC_ETHER_MACE,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_AV,
+               .floppy_type    = MAC_FLOPPY_UNSUPPORTED, /* New Age */
        }, {
                .ident          = MAC_MODEL_Q900,
                .name           = "Quadra 900",
@@ -472,7 +472,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_IOP,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_IOP,
+               .floppy_type    = MAC_FLOPPY_SWIM_IOP, /* SWIM */
        }, {
                .ident          = MAC_MODEL_Q950,
                .name           = "Quadra 950",
@@ -482,7 +482,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_IOP,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_IOP,
+               .floppy_type    = MAC_FLOPPY_SWIM_IOP, /* SWIM */
        },
 
        /*
@@ -497,7 +497,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P475,
                .name           = "Performa 475",
@@ -506,7 +506,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_QUADRA,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P475F,
                .name           = "Performa 475",
@@ -515,7 +515,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_QUADRA,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P520,
                .name           = "Performa 520",
@@ -524,7 +524,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P550,
                .name           = "Performa 550",
@@ -533,7 +533,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        },
        /* These have the comm slot, and therefore possibly SONIC ethernet */
        {
@@ -544,7 +544,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_QUADRA,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS_COMM,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P588,
                .name           = "Performa 588",
@@ -554,7 +554,7 @@ static struct mac_model mac_data_table[] = {
                .ide_type       = MAC_IDE_QUADRA,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_PDS_COMM,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_TV,
                .name           = "TV",
@@ -562,7 +562,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_IICI,
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_P600,
                .name           = "Performa 600",
@@ -571,7 +571,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_LC,
                .scc_type       = MAC_SCC_II,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_LC, /* SWIM */
        },
 
        /*
@@ -588,7 +588,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_C650,
                .name           = "Centris 650",
@@ -598,7 +598,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR1,
+               .floppy_type    = MAC_FLOPPY_QUADRA, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_C660,
                .name           = "Centris 660AV",
@@ -608,7 +608,7 @@ static struct mac_model mac_data_table[] = {
                .scc_type       = MAC_SCC_PSC,
                .ether_type     = MAC_ETHER_MACE,
                .expansion_type = MAC_EXP_PDS_NUBUS,
-               .floppy_type    = MAC_FLOPPY_AV,
+               .floppy_type    = MAC_FLOPPY_UNSUPPORTED, /* New Age */
        },
 
        /*
@@ -624,7 +624,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB145,
                .name           = "PowerBook 145",
@@ -632,7 +632,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB150,
                .name           = "PowerBook 150",
@@ -641,7 +641,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .ide_type       = MAC_IDE_PB,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB160,
                .name           = "PowerBook 160",
@@ -649,7 +649,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB165,
                .name           = "PowerBook 165",
@@ -657,7 +657,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB165C,
                .name           = "PowerBook 165c",
@@ -665,7 +665,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB170,
                .name           = "PowerBook 170",
@@ -673,7 +673,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB180,
                .name           = "PowerBook 180",
@@ -681,7 +681,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB180C,
                .name           = "PowerBook 180c",
@@ -689,7 +689,7 @@ static struct mac_model mac_data_table[] = {
                .via_type       = MAC_VIA_QUADRA,
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB190,
                .name           = "PowerBook 190",
@@ -698,7 +698,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .ide_type       = MAC_IDE_BABOON,
                .scc_type       = MAC_SCC_QUADRA,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM 2 */
        }, {
                .ident          = MAC_MODEL_PB520,
                .name           = "PowerBook 520",
@@ -707,7 +707,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_OLD,
                .scc_type       = MAC_SCC_QUADRA,
                .ether_type     = MAC_ETHER_SONIC,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM 2 */
        },
 
        /*
@@ -724,7 +724,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB230,
                .name           = "PowerBook Duo 230",
@@ -733,7 +733,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB250,
                .name           = "PowerBook Duo 250",
@@ -742,7 +742,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB270C,
                .name           = "PowerBook Duo 270c",
@@ -751,7 +751,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB280,
                .name           = "PowerBook Duo 280",
@@ -760,7 +760,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        }, {
                .ident          = MAC_MODEL_PB280C,
                .name           = "PowerBook Duo 280c",
@@ -769,7 +769,7 @@ static struct mac_model mac_data_table[] = {
                .scsi_type      = MAC_SCSI_DUO,
                .scc_type       = MAC_SCC_QUADRA,
                .expansion_type = MAC_EXP_NUBUS,
-               .floppy_type    = MAC_FLOPPY_SWIM_ADDR2,
+               .floppy_type    = MAC_FLOPPY_OLD, /* SWIM */
        },
 
        /*
@@ -960,7 +960,7 @@ static const struct resource mac_scsi_ccl_rsrc[] __initconst = {
 
 int __init mac_platform_init(void)
 {
-       u8 *swim_base;
+       phys_addr_t swim_base = 0;
 
        if (!MACH_IS_MAC)
                return -ENODEV;
@@ -977,22 +977,22 @@ int __init mac_platform_init(void)
         */
 
        switch (macintosh_config->floppy_type) {
-       case MAC_FLOPPY_SWIM_ADDR1:
-               swim_base = (u8 *)(VIA1_BASE + 0x1E000);
+       case MAC_FLOPPY_QUADRA:
+               swim_base = 0x5001E000;
                break;
-       case MAC_FLOPPY_SWIM_ADDR2:
-               swim_base = (u8 *)(VIA1_BASE + 0x16000);
+       case MAC_FLOPPY_OLD:
+               swim_base = 0x50016000;
                break;
-       default:
-               swim_base = NULL;
+       case MAC_FLOPPY_LC:
+               swim_base = 0x50F16000;
                break;
        }
 
        if (swim_base) {
                struct resource swim_rsrc = {
                        .flags = IORESOURCE_MEM,
-                       .start = (resource_size_t)swim_base,
-                       .end   = (resource_size_t)swim_base + 0x1FFF,
+                       .start = swim_base,
+                       .end   = swim_base + 0x1FFF,
                };
 
                platform_device_register_simple("swim", -1, &swim_rsrc, 1);
index 6656602..f14ad05 100644 (file)
@@ -103,7 +103,6 @@ CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
-CONFIG_SGI_IOC4=m
 CONFIG_EEPROM_LEGACY=y
 CONFIG_EEPROM_MAX6875=y
 CONFIG_IDE=y
index 572cab9..3708840 100644 (file)
@@ -46,7 +46,6 @@ CONFIG_CONNECTOR=y
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
-CONFIG_SGI_IOC4=y
 CONFIG_RAID_ATTRS=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
index ae93a94..507ad91 100644 (file)
@@ -117,7 +117,6 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_SGI_IOC4=m
 CONFIG_SCSI=m
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=m
index 0f4b09f..8762e75 100644 (file)
@@ -198,7 +198,6 @@ CONFIG_BLK_DEV_SX8=m
 CONFIG_BLK_DEV_RAM=m
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-CONFIG_SGI_IOC4=m
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
index 6883ea4..bb0b1b2 100644 (file)
@@ -49,7 +49,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=9220
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-CONFIG_SGI_IOC4=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=y
index 52cf96e..cbc7cda 100644 (file)
@@ -46,6 +46,7 @@ static inline uint64_t CVMX_SLI_PCIE_MSI_RCV_FUNC(void)
        case OCTEON_CN78XX & OCTEON_FAMILY_MASK:
                if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X))
                        return 0x0000000000003CB0ull;
+               /* Else, fall through */
        default:
                return 0x0000000000023CB0ull;
        }
index fe61513..330b19f 100644 (file)
@@ -316,6 +316,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                                regs->uregs[0] = -EINTR;
                                break;
                        }
+                       /* Else, fall through */
                case -ERESTARTNOINTR:
                        regs->uregs[0] = regs->orig_r0;
                        regs->ipc -= 4;
@@ -360,6 +361,7 @@ static void do_signal(struct pt_regs *regs)
                switch (regs->uregs[0]) {
                case -ERESTART_RESTARTBLOCK:
                        regs->uregs[15] = __NR_restart_syscall;
+                       /* Fall through */
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
index 6d732e4..2e757c7 100644 (file)
@@ -61,6 +61,8 @@ config PARISC
        select HAVE_KRETPROBES
        select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1)
        select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
+       select HAVE_KPROBES_ON_FTRACE
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
@@ -344,6 +346,29 @@ config NR_CPUS
        depends on SMP
        default "4"
 
+config KEXEC
+       bool "Kexec system call"
+       select KEXEC_CORE
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is independent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         It is an ongoing process to be certain the hardware in a machine
+         shutdown, so do not be surprised if this code does not
+         initially work for you.
+
+config KEXEC_FILE
+       bool "kexec file based system call"
+       select KEXEC_CORE
+       select KEXEC_ELF
+       help
+         This enables the kexec_file_load() System call. This is
+         file based and takes file descriptors as system call argument
+         for kernel and initramfs as opposed to list of segments as
+         accepted by previous system call.
+
 endmenu
 
 
index 793d8ba..0ec54f4 100644 (file)
@@ -8,6 +8,7 @@
 #define ALT_COND_NO_ICACHE     0x04    /* if system has no i-cache  */
 #define ALT_COND_NO_SPLIT_TLB  0x08    /* if split_tlb == 0  */
 #define ALT_COND_NO_IOC_FDC    0x10    /* if I/O cache does not need flushes */
+#define ALT_COND_RUN_ON_QEMU   0x20    /* if running on QEMU */
 
 #define INSN_PxTLB     0x02            /* modify pdtlb, pitlb */
 #define INSN_NOP       0x08000240      /* nop */
@@ -21,7 +22,7 @@
 
 struct alt_instr {
        s32 orig_offset;        /* offset to original instructions */
-       u32 len;                /* end of original instructions */
+       s32 len;                /* end of original instructions */
        u32 cond;               /* see ALT_COND_XXX */
        u32 replacement;        /* replacement instruction or code */
 };
@@ -40,12 +41,20 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
 
 #else
 
+/* to replace one single instructions by a new instruction */
 #define ALTERNATIVE(from, to, cond, replacement)\
        .section .altinstructions, "aw" !       \
        .word (from - .), (to - from)/4 !       \
        .word cond, replacement         !       \
        .previous
 
+/* to replace multiple instructions by new code */
+#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\
+       .section .altinstructions, "aw" !       \
+       .word (from - .), -num_instructions !   \
+       .word cond, (new_instr_ptr - .) !       \
+       .previous
+
 #endif  /*  __ASSEMBLY__  */
 
 #endif /* __ASM_PARISC_ALTERNATIVE_H */
index 288da73..e480b2c 100644 (file)
@@ -30,6 +30,7 @@
 enum fixed_addresses {
        /* Support writing RO kernel text via kprobes, jump labels, etc. */
        FIX_TEXT_POKE0,
+       FIX_TEXT_KEXEC,
        FIX_BITMAP_COUNT
 };
 
index 958c0aa..a7cf0d0 100644 (file)
@@ -8,6 +8,7 @@ extern void mcount(void);
 #define MCOUNT_ADDR            ((unsigned long)mcount)
 #define MCOUNT_INSN_SIZE       4
 #define CC_USING_NOP_MCOUNT
+#define ARCH_SUPPORTS_FTRACE_OPS 1
 extern unsigned long sys_call_table[];
 
 extern unsigned long return_address(unsigned int);
diff --git a/arch/parisc/include/asm/kexec.h b/arch/parisc/include/asm/kexec.h
new file mode 100644 (file)
index 0000000..a99ea74
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_KEXEC_H
+#define _ASM_PARISC_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+#define KEXEC_CONTROL_PAGE_SIZE        4096
+
+#define KEXEC_ARCH KEXEC_ARCH_PARISC
+#define ARCH_HAS_KIMAGE_ARCH
+
+#ifndef __ASSEMBLY__
+
+struct kimage_arch {
+       unsigned long initrd_start;
+       unsigned long initrd_end;
+       unsigned long cmdline;
+};
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                   struct pt_regs *oldregs)
+{
+       /* Dummy implementation for now */
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _ASM_PARISC_KEXEC_H */
index 19bb2e4..b388d81 100644 (file)
@@ -91,6 +91,7 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
                  unsigned long inptr, unsigned long outputr,
                  unsigned long glob_cfg);
 
+int __pdc_cpu_rendezvous(void);
 static inline char * os_id_to_string(u16 os_id) {
        switch(os_id) {
        case OS_ID_NONE:        return "No OS";
index a39b079..6d58c17 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _PARISC_PGTABLE_H
 #define _PARISC_PGTABLE_H
 
+#include <asm/page.h>
 #include <asm-generic/4level-fixup.h>
 
 #include <asm/fixmap.h>
@@ -98,8 +99,6 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 
 #endif /* !__ASSEMBLY__ */
 
-#include <asm/page.h>
-
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
index f6e1132..4a0c9db 100644 (file)
@@ -8,4 +8,19 @@ extern void * memset(void *, int, size_t);
 #define __HAVE_ARCH_MEMCPY
 void * memcpy(void * dest,const void *src,size_t count);
 
+#define __HAVE_ARCH_STRLEN
+extern size_t strlen(const char *s);
+
+#define __HAVE_ARCH_STRCPY
+extern char *strcpy(char *dest, const char *src);
+
+#define __HAVE_ARCH_STRNCPY
+extern char *strncpy(char *dest, const char *src, size_t count);
+
+#define __HAVE_ARCH_STRCAT
+extern char *strcat(char *dest, const char *src);
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, size_t);
+
 #endif
index c232266..2663c8f 100644 (file)
@@ -37,3 +37,5 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER)   += ftrace.o
 obj-$(CONFIG_JUMP_LABEL)               += jump_label.o
 obj-$(CONFIG_KGDB)                     += kgdb.o
 obj-$(CONFIG_KPROBES)                  += kprobes.o
+obj-$(CONFIG_KEXEC)                    += kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)               += kexec_file.o
index ca1f5ca..3c66d5c 100644 (file)
@@ -28,7 +28,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
 
        for (entry = start; entry < end; entry++, index++) {
 
-               u32 *from, len, cond, replacement;
+               u32 *from, cond, replacement;
+               s32 len;
 
                from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
                len = entry->len;
@@ -49,6 +50,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
                        continue;
                if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
                        continue;
+               if ((cond & ALT_COND_RUN_ON_QEMU) && !running_on_qemu)
+                       continue;
 
                /*
                 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
@@ -74,11 +77,19 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
                if (replacement == INSN_NOP && len > 1)
                        replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
 
-               pr_debug("Do    %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
-                       index, cond, len, from, replacement);
-
-               /* Replace instruction */
-               *from = replacement;
+               pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
+                       index, cond, len, replacement, from, from);
+
+               if (len < 0) {
+                       /* Replace multiple instruction by new code */
+                       u32 *source;
+                       len = -len;
+                       source = (u32 *)((ulong)&entry->replacement + entry->replacement);
+                       memcpy(from, source, 4 * len);
+               } else {
+                       /* Replace by one instruction */
+                       *from = replacement;
+               }
                applied++;
        }
 
index d9d3387..1d1d748 100644 (file)
@@ -1996,6 +1996,7 @@ _mcount:
         * calling mcount(), and 2 instructions for ftrace_stub().  That way we
         * have all on one L1 cacheline.
         */
+       ldi     0, %arg3
        b       ftrace_function_trampoline
        copy    %r3, %arg2      /* caller original %sp */
 ftrace_stub:
@@ -2048,6 +2049,7 @@ ftrace_caller:
        LDREG   0(%r3), %r25
        copy    %rp, %r26
        ldo     -8(%r25), %r25
+       ldi     0, %r23         /* no pt_regs */
        b,l     ftrace_function_trampoline, %rp
        copy    %r3, %r24
 
@@ -2075,6 +2077,103 @@ ftrace_caller:
 
 ENDPROC_CFI(ftrace_caller)
 
+#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS
+ENTRY_CFI(ftrace_regs_caller,caller,frame=FTRACE_FRAME_SIZE+PT_SZ_ALGN,
+       CALLS,SAVE_RP,SAVE_SP)
+ftrace_regs_caller:
+       .global ftrace_regs_caller
+
+       ldo     -FTRACE_FRAME_SIZE(%sp), %r1
+       STREG   %rp, -RP_OFFSET(%r1)
+
+       copy    %sp, %r1
+       ldo     PT_SZ_ALGN(%sp), %sp
+
+       STREG   %rp, PT_GR2(%r1)
+       STREG   %r3, PT_GR3(%r1)
+       STREG   %r4, PT_GR4(%r1)
+       STREG   %r5, PT_GR5(%r1)
+       STREG   %r6, PT_GR6(%r1)
+       STREG   %r7, PT_GR7(%r1)
+       STREG   %r8, PT_GR8(%r1)
+       STREG   %r9, PT_GR9(%r1)
+       STREG   %r10, PT_GR10(%r1)
+       STREG   %r11, PT_GR11(%r1)
+       STREG   %r12, PT_GR12(%r1)
+       STREG   %r13, PT_GR13(%r1)
+       STREG   %r14, PT_GR14(%r1)
+       STREG   %r15, PT_GR15(%r1)
+       STREG   %r16, PT_GR16(%r1)
+       STREG   %r17, PT_GR17(%r1)
+       STREG   %r18, PT_GR18(%r1)
+       STREG   %r19, PT_GR19(%r1)
+       STREG   %r20, PT_GR20(%r1)
+       STREG   %r21, PT_GR21(%r1)
+       STREG   %r22, PT_GR22(%r1)
+       STREG   %r23, PT_GR23(%r1)
+       STREG   %r24, PT_GR24(%r1)
+       STREG   %r25, PT_GR25(%r1)
+       STREG   %r26, PT_GR26(%r1)
+       STREG   %r27, PT_GR27(%r1)
+       STREG   %r28, PT_GR28(%r1)
+       STREG   %r29, PT_GR29(%r1)
+       STREG   %r30, PT_GR30(%r1)
+       STREG   %r31, PT_GR31(%r1)
+       mfctl   %cr11, %r26
+       STREG   %r26, PT_SAR(%r1)
+
+       copy    %rp, %r26
+       LDREG   -FTRACE_FRAME_SIZE-PT_SZ_ALGN(%sp), %r25
+       ldo     -8(%r25), %r25
+       copy    %r3, %arg2
+       b,l     ftrace_function_trampoline, %rp
+       copy    %r1, %arg3 /* struct pt_regs */
+
+       ldo     -PT_SZ_ALGN(%sp), %r1
+
+       LDREG   PT_SAR(%r1), %rp
+       mtctl   %rp, %cr11
+
+       LDREG   PT_GR2(%r1), %rp
+       LDREG   PT_GR3(%r1), %r3
+       LDREG   PT_GR4(%r1), %r4
+       LDREG   PT_GR5(%r1), %r5
+       LDREG   PT_GR6(%r1), %r6
+       LDREG   PT_GR7(%r1), %r7
+       LDREG   PT_GR8(%r1), %r8
+       LDREG   PT_GR9(%r1), %r9
+       LDREG   PT_GR10(%r1),%r10
+       LDREG   PT_GR11(%r1),%r11
+       LDREG   PT_GR12(%r1),%r12
+       LDREG   PT_GR13(%r1),%r13
+       LDREG   PT_GR14(%r1),%r14
+       LDREG   PT_GR15(%r1),%r15
+       LDREG   PT_GR16(%r1),%r16
+       LDREG   PT_GR17(%r1),%r17
+       LDREG   PT_GR18(%r1),%r18
+       LDREG   PT_GR19(%r1),%r19
+       LDREG   PT_GR20(%r1),%r20
+       LDREG   PT_GR21(%r1),%r21
+       LDREG   PT_GR22(%r1),%r22
+       LDREG   PT_GR23(%r1),%r23
+       LDREG   PT_GR24(%r1),%r24
+       LDREG   PT_GR25(%r1),%r25
+       LDREG   PT_GR26(%r1),%r26
+       LDREG   PT_GR27(%r1),%r27
+       LDREG   PT_GR28(%r1),%r28
+       LDREG   PT_GR29(%r1),%r29
+       LDREG   PT_GR30(%r1),%r30
+       LDREG   PT_GR31(%r1),%r31
+
+       ldo     -PT_SZ_ALGN(%sp), %sp
+       LDREGM  -FTRACE_FRAME_SIZE(%sp), %r1
+       /* Adjust return point to jump back to beginning of traced function */
+       ldo     -4(%r1), %r1
+       bv,n    (%r1)
+
+ENDPROC_CFI(ftrace_regs_caller)
+
+#endif
 #endif
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
index 58cc08e..1d976f2 100644 (file)
@@ -311,6 +311,19 @@ int pdc_chassis_disp(unsigned long disp)
        return retval;
 }
 
+/**
+ * pdc_cpu_rendenzvous - Stop currently executing CPU
+ * @retval: -1 on error, 0 on success
+ */
+int __pdc_cpu_rendezvous(void)
+{
+       if (is_pdc_pat())
+               return mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_RENDEZVOUS);
+       else
+               return mem_pdc_call(PDC_PROC, 1, 0);
+}
+
+
 /**
  * pdc_chassis_warn - Fetches chassis warnings
  * @retval: -1 on error, 0 on success
index b6fb30f..b836fc6 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/init.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
 
 #include <asm/assembly.h>
 #include <asm/sections.h>
@@ -48,17 +50,22 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
 
 void notrace __hot ftrace_function_trampoline(unsigned long parent,
                                unsigned long self_addr,
-                               unsigned long org_sp_gr3)
+                               unsigned long org_sp_gr3,
+                               struct pt_regs *regs)
 {
 #ifndef CONFIG_DYNAMIC_FTRACE
        extern ftrace_func_t ftrace_trace_function;
 #endif
-       if (ftrace_trace_function != ftrace_stub)
-               ftrace_trace_function(self_addr, parent, NULL, NULL);
+       extern struct ftrace_ops *function_trace_op;
+
+       if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED &&
+           ftrace_trace_function != ftrace_stub)
+               ftrace_trace_function(self_addr, parent,
+                               function_trace_op, regs);
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
-               ftrace_graph_entry != ftrace_graph_entry_stub) {
+           ftrace_graph_entry != ftrace_graph_entry_stub) {
                unsigned long *parent_rp;
 
                /* calculate pointer to %rp in stack */
@@ -96,6 +103,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        return 0;
 }
 
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+                       unsigned long addr)
+{
+       return 0;
+}
+
 unsigned long ftrace_call_adjust(unsigned long addr)
 {
        return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
@@ -187,3 +200,46 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        return 0;
 }
 #endif
+
+#ifdef CONFIG_KPROBES_ON_FTRACE
+void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+                          struct ftrace_ops *ops, struct pt_regs *regs)
+{
+       struct kprobe_ctlblk *kcb;
+       struct kprobe *p = get_kprobe((kprobe_opcode_t *)ip);
+
+       if (unlikely(!p) || kprobe_disabled(p))
+               return;
+
+       if (kprobe_running()) {
+               kprobes_inc_nmissed_count(p);
+               return;
+       }
+
+       __this_cpu_write(current_kprobe, p);
+
+       kcb = get_kprobe_ctlblk();
+       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+       regs->iaoq[0] = ip;
+       regs->iaoq[1] = ip + 4;
+
+       if (!p->pre_handler || !p->pre_handler(p, regs)) {
+               regs->iaoq[0] = ip + 4;
+               regs->iaoq[1] = ip + 8;
+
+               if (unlikely(p->post_handler)) {
+                       kcb->kprobe_status = KPROBE_HIT_SSDONE;
+                       p->post_handler(p, regs, 0);
+               }
+       }
+       __this_cpu_write(current_kprobe, NULL);
+}
+NOKPROBE_SYMBOL(kprobe_ftrace_handler);
+
+int arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+       p->ainsn.insn = NULL;
+       return 0;
+}
+#endif
diff --git a/arch/parisc/kernel/kexec.c b/arch/parisc/kernel/kexec.c
new file mode 100644 (file)
index 0000000..5eb7f30
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+#include <asm/sections.h>
+
+extern void relocate_new_kernel(unsigned long head,
+                               unsigned long start,
+                               unsigned long phys);
+
+extern const unsigned int relocate_new_kernel_size;
+extern unsigned int kexec_initrd_start_offset;
+extern unsigned int kexec_initrd_end_offset;
+extern unsigned int kexec_cmdline_offset;
+extern unsigned int kexec_free_mem_offset;
+
+static void kexec_show_segment_info(const struct kimage *kimage,
+                                   unsigned long n)
+{
+       pr_debug("    segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
+                       n,
+                       kimage->segment[n].mem,
+                       kimage->segment[n].mem + kimage->segment[n].memsz,
+                       (unsigned long)kimage->segment[n].memsz,
+                       (unsigned long)kimage->segment[n].memsz /  PAGE_SIZE);
+}
+
+static void kexec_image_info(const struct kimage *kimage)
+{
+       unsigned long i;
+
+       pr_debug("kexec kimage info:\n");
+       pr_debug("  type:        %d\n", kimage->type);
+       pr_debug("  start:       %lx\n", kimage->start);
+       pr_debug("  head:        %lx\n", kimage->head);
+       pr_debug("  nr_segments: %lu\n", kimage->nr_segments);
+
+       for (i = 0; i < kimage->nr_segments; i++)
+               kexec_show_segment_info(kimage, i);
+
+#ifdef CONFIG_KEXEC_FILE
+       if (kimage->file_mode) {
+               pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len,
+                        kimage->cmdline_buf);
+       }
+#endif
+}
+
+void machine_kexec_cleanup(struct kimage *kimage)
+{
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
+void machine_shutdown(void)
+{
+       smp_send_stop();
+       while (num_online_cpus() > 1) {
+               cpu_relax();
+               mdelay(1);
+       }
+}
+
+void machine_kexec(struct kimage *image)
+{
+#ifdef CONFIG_64BIT
+       Elf64_Fdesc desc;
+#endif
+       void (*reloc)(unsigned long head,
+                     unsigned long start,
+                     unsigned long phys);
+
+       unsigned long phys = page_to_phys(image->control_code_page);
+       void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC);
+       struct kimage_arch *arch = &image->arch;
+
+       set_fixmap(FIX_TEXT_KEXEC, phys);
+
+       flush_cache_all();
+
+#ifdef CONFIG_64BIT
+       reloc = (void *)&desc;
+       desc.addr = (long long)virt;
+#else
+       reloc = (void *)virt;
+#endif
+
+       memcpy(virt, dereference_function_descriptor(relocate_new_kernel),
+               relocate_new_kernel_size);
+
+       *(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline;
+       *(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start;
+       *(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end;
+       *(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free;
+
+       flush_cache_all();
+       flush_tlb_all();
+       local_irq_disable();
+
+       reloc(image->head & PAGE_MASK, image->start, phys);
+}
+
+int machine_kexec_prepare(struct kimage *image)
+{
+       kexec_image_info(image);
+       return 0;
+}
diff --git a/arch/parisc/kernel/kexec_file.c b/arch/parisc/kernel/kexec_file.c
new file mode 100644 (file)
index 0000000..8c53420
--- /dev/null
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Load ELF vmlinux file for the kexec_file_load syscall.
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ */
+#include <linux/elf.h>
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+static void *elf_load(struct kimage *image, char *kernel_buf,
+                       unsigned long kernel_len, char *initrd,
+                       unsigned long initrd_len, char *cmdline,
+                       unsigned long cmdline_len)
+{
+       int ret, i;
+       unsigned long kernel_load_addr;
+       struct elfhdr ehdr;
+       struct kexec_elf_info elf_info;
+       struct kexec_buf kbuf = { .image = image, .buf_min = 0,
+                                 .buf_max = -1UL, };
+
+       ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+       if (ret)
+               goto out;
+
+       ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
+       if (ret)
+               goto out;
+
+       image->start = __pa(elf_info.ehdr->e_entry);
+
+       for (i = 0; i < image->nr_segments; i++)
+               image->segment[i].mem = __pa(image->segment[i].mem);
+
+       pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n",
+                kernel_load_addr, image->start);
+
+       if (initrd != NULL) {
+               kbuf.buffer = initrd;
+               kbuf.bufsz = kbuf.memsz = initrd_len;
+               kbuf.buf_align = PAGE_SIZE;
+               kbuf.top_down = false;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+               ret = kexec_add_buffer(&kbuf);
+               if (ret)
+                       goto out;
+
+               pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem);
+               image->arch.initrd_start = kbuf.mem;
+               image->arch.initrd_end = kbuf.mem + initrd_len;
+       }
+
+       if (cmdline != NULL) {
+               kbuf.buffer = cmdline;
+               kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8);
+               kbuf.buf_align = PAGE_SIZE;
+               kbuf.top_down = false;
+               kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE;
+               kbuf.buf_max = kernel_load_addr;
+               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+               ret = kexec_add_buffer(&kbuf);
+               if (ret)
+                       goto out;
+
+               pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem);
+               image->arch.cmdline = kbuf.mem;
+       }
+out:
+       return NULL;
+}
+
+const struct kexec_file_ops kexec_elf_ops = {
+       .probe = kexec_elf_probe,
+       .load = elf_load,
+};
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+       &kexec_elf_ops,
+       NULL
+};
index 5d7f269..77ec518 100644 (file)
@@ -281,10 +281,6 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
 {
        return p->addr == trampoline_p.addr;
 }
-bool arch_kprobe_on_func_entry(unsigned long offset)
-{
-       return !offset;
-}
 
 int __init arch_init_kprobes(void)
 {
index df46b0e..fa092ed 100644 (file)
@@ -174,6 +174,15 @@ fdtdone:
 
 2:      bv             %r0(%r2)
        nop
+
+       /*
+        * When running in qemu, drop whole flush_tlb_all_local function and
+        * replace by one pdtlbe instruction, for which QEMU will drop all
+        * local TLB entries.
+        */
+3:     pdtlbe          %r0(%sr1,%r0)
+       bv,n            %r0(%r2)
+       ALTERNATIVE_CODE(flush_tlb_all_local, 2, ALT_COND_RUN_ON_QEMU, 3b)
 ENDPROC_CFI(flush_tlb_all_local)
 
        .import cache_info,data
index e8a6a75..8ed409e 100644 (file)
 
 #include <linux/string.h>
 EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
 
 #include <linux/atomic.h>
 EXPORT_SYMBOL(__xchg8);
index bc41ca2..cf285b1 100644 (file)
 #define DBG_RES(x...)
 #endif
 
-/* To be used as: mdelay(pci_post_reset_delay);
- *
- * post_reset is the time the kernel should stall to prevent anyone from
- * accessing the PCI bus once #RESET is de-asserted. 
- * PCI spec somewhere says 1 second but with multi-PCI bus systems,
- * this makes the boot time much longer than necessary.
- * 20ms seems to work for all the HP PCI implementations to date.
- *
- * #define pci_post_reset_delay 50
- */
-
 struct pci_port_ops *pci_port __ro_after_init;
 struct pci_bios_ops *pci_bios __ro_after_init;
 
diff --git a/arch/parisc/kernel/relocate_kernel.S b/arch/parisc/kernel/relocate_kernel.S
new file mode 100644 (file)
index 0000000..2561e52
--- /dev/null
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <linux/kexec.h>
+
+#include <asm/assembly.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/psw.h>
+
+.level PA_ASM_LEVEL
+
+.macro kexec_param name
+.align 8
+ENTRY(kexec\()_\name)
+#ifdef CONFIG_64BIT
+       .dword 0
+#else
+       .word 0
+#endif
+
+ENTRY(kexec\()_\name\()_offset)
+       .word kexec\()_\name - relocate_new_kernel
+.endm
+
+.text
+
+/* args:
+ * r26 - kimage->head
+ * r25 - start address of kernel
+ * r24 - physical address of relocate code
+ */
+
+ENTRY_CFI(relocate_new_kernel)
+0:     copy    %arg1, %rp
+       /* disable I and Q bit, so we are allowed to execute RFI */
+       rsm PSW_SM_I, %r0
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+       rsm PSW_SM_Q, %r0
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+       /*
+        * After return-from-interrupt, we want to run without Code/Data
+        * translation enabled just like on a normal boot.
+        */
+
+       /* calculate new physical execution address */
+       ldo     1f-0b(%arg2), %r1
+       mtctl   %r0, %cr17 /* IIASQ */
+       mtctl   %r0, %cr17 /* IIASQ */
+       mtctl   %r1, %cr18 /* IIAOQ */
+       ldo     4(%r1),%r1
+       mtctl   %r1, %cr18 /* IIAOQ */
+#ifdef CONFIG_64BIT
+       depdi,z 1, PSW_W_BIT, 1, %r1
+       mtctl   %r1, %cr22 /* IPSW */
+#else
+       mtctl   %r0, %cr22 /* IPSW */
+#endif
+       /* lets go... */
+       rfi
+1:     nop
+       nop
+
+.Lloop:
+       LDREG,ma        REG_SZ(%arg0), %r3
+       /* If crash kernel, no copy needed */
+       cmpib,COND(=),n 0,%r3,boot
+
+       bb,<,n          %r3, 31 - IND_DONE_BIT, boot
+       bb,>=,n         %r3, 31 - IND_INDIRECTION_BIT, .Lnotind
+       /* indirection, load and restart */
+       movb            %r3, %arg0, .Lloop
+       depi            0, 31, PAGE_SHIFT, %arg0
+
+.Lnotind:
+       bb,>=,n         %r3, 31 - IND_DESTINATION_BIT, .Lnotdest
+       b               .Lloop
+       copy            %r3, %r20
+
+.Lnotdest:
+       bb,>=           %r3, 31 - IND_SOURCE_BIT, .Lloop
+       depi            0, 31, PAGE_SHIFT, %r3
+       copy            %r3, %r21
+
+       /* copy page */
+       copy            %r0, %r18
+       zdepi           1, 31 - PAGE_SHIFT, 1, %r18
+       add             %r20, %r18, %r17
+
+       depi            0, 31, PAGE_SHIFT, %r20
+.Lcopy:
+       copy            %r20, %r12
+       LDREG,ma        REG_SZ(%r21), %r8
+       LDREG,ma        REG_SZ(%r21), %r9
+       LDREG,ma        REG_SZ(%r21), %r10
+       LDREG,ma        REG_SZ(%r21), %r11
+       STREG,ma        %r8, REG_SZ(%r20)
+       STREG,ma        %r9, REG_SZ(%r20)
+       STREG,ma        %r10, REG_SZ(%r20)
+       STREG,ma        %r11, REG_SZ(%r20)
+
+#ifndef CONFIG_64BIT
+       LDREG,ma        REG_SZ(%r21), %r8
+       LDREG,ma        REG_SZ(%r21), %r9
+       LDREG,ma        REG_SZ(%r21), %r10
+       LDREG,ma        REG_SZ(%r21), %r11
+       STREG,ma        %r8, REG_SZ(%r20)
+       STREG,ma        %r9, REG_SZ(%r20)
+       STREG,ma        %r10, REG_SZ(%r20)
+       STREG,ma        %r11, REG_SZ(%r20)
+#endif
+
+       fdc             %r0(%r12)
+       cmpb,COND(<<)   %r20,%r17,.Lcopy
+       fic             (%sr4, %r12)
+       b,n             .Lloop
+
+boot:
+       mtctl   %r0, %cr15
+
+       LDREG   kexec_free_mem-0b(%arg2), %arg0
+       LDREG   kexec_cmdline-0b(%arg2), %arg1
+       LDREG   kexec_initrd_end-0b(%arg2), %arg3
+       LDREG   kexec_initrd_start-0b(%arg2), %arg2
+       bv,n %r0(%rp)
+
+ENDPROC_CFI(relocate_new_kernel);
+
+ENTRY(relocate_new_kernel_size)
+       .word relocate_new_kernel_size - relocate_new_kernel
+
+kexec_param cmdline
+kexec_param initrd_start
+kexec_param initrd_end
+kexec_param free_mem
index cbd074b..e202c37 100644 (file)
@@ -109,6 +109,7 @@ halt_processor(void)
        /* REVISIT : does PM *know* this CPU isn't available? */
        set_cpu_online(smp_processor_id(), false);
        local_irq_disable();
+       __pdc_cpu_rendezvous();
        for (;;)
                ;
 }
index 670d137..285ff51 100644 (file)
 352    common  pkey_alloc              sys_pkey_alloc
 353    common  pkey_free               sys_pkey_free
 354    common  rseq                    sys_rseq
-# 355 through 402 are unassigned to sync up with generic numbers
+355    common  kexec_file_load         sys_kexec_file_load             sys_kexec_file_load
+# up to 402 is unassigned and reserved for arch specific syscalls
 403    32      clock_gettime64                 sys_clock_gettime               sys_clock_gettime
 404    32      clock_settime64                 sys_clock_settime               sys_clock_settime
 405    32      clock_adjtime64                 sys_clock_adjtime               sys_clock_adjtime
index 58dcf44..82fc011 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/bug.h>
 #include <linux/ratelimit.h>
 #include <linux/uaccess.h>
+#include <linux/kdebug.h>
 
 #include <asm/assembly.h>
 #include <asm/io.h>
@@ -414,6 +415,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
 {
        static DEFINE_SPINLOCK(terminate_lock);
 
+       (void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP);
        bust_spinlocks(1);
 
        set_eiem(0);
index 7b19766..2d7a997 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for parisc-specific library files
 #
 
-lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \
-          ucmpdi2.o delay.o
+lib-y  := lusercopy.o bitops.o checksum.o io.o memcpy.o \
+          ucmpdi2.o delay.o string.o
 
 obj-y  := iomap.o
diff --git a/arch/parisc/lib/memset.c b/arch/parisc/lib/memset.c
deleted file mode 100644 (file)
index 1d7929b..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-/* Slight modifications for pa-risc linux - Paul Bame <bame@debian.org> */
-
-#include <linux/types.h>
-#include <asm/string.h>
-
-#define OPSIZ (BITS_PER_LONG/8)
-typedef unsigned long op_t;
-
-void *
-memset (void *dstpp, int sc, size_t len)
-{
-  unsigned int c = sc;
-  long int dstp = (long int) dstpp;
-
-  if (len >= 8)
-    {
-      size_t xlen;
-      op_t cccc;
-
-      cccc = (unsigned char) c;
-      cccc |= cccc << 8;
-      cccc |= cccc << 16;
-      if (OPSIZ > 4)
-       /* Do the shift in two steps to avoid warning if long has 32 bits.  */
-       cccc |= (cccc << 16) << 16;
-
-      /* There are at least some bytes to set.
-        No need to test for LEN == 0 in this alignment loop.  */
-      while (dstp % OPSIZ != 0)
-       {
-         ((unsigned char *) dstp)[0] = c;
-         dstp += 1;
-         len -= 1;
-       }
-
-      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
-      xlen = len / (OPSIZ * 8);
-      while (xlen > 0)
-       {
-         ((op_t *) dstp)[0] = cccc;
-         ((op_t *) dstp)[1] = cccc;
-         ((op_t *) dstp)[2] = cccc;
-         ((op_t *) dstp)[3] = cccc;
-         ((op_t *) dstp)[4] = cccc;
-         ((op_t *) dstp)[5] = cccc;
-         ((op_t *) dstp)[6] = cccc;
-         ((op_t *) dstp)[7] = cccc;
-         dstp += 8 * OPSIZ;
-         xlen -= 1;
-       }
-      len %= OPSIZ * 8;
-
-      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
-      xlen = len / OPSIZ;
-      while (xlen > 0)
-       {
-         ((op_t *) dstp)[0] = cccc;
-         dstp += OPSIZ;
-         xlen -= 1;
-       }
-      len %= OPSIZ;
-    }
-
-  /* Write the last few bytes.  */
-  while (len > 0)
-    {
-      ((unsigned char *) dstp)[0] = c;
-      dstp += 1;
-      len -= 1;
-    }
-
-  return dstpp;
-}
diff --git a/arch/parisc/lib/string.S b/arch/parisc/lib/string.S
new file mode 100644 (file)
index 0000000..4a64264
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *    PA-RISC assembly string functions
+ *
+ *    Copyright (C) 2019 Helge Deller <deller@gmx.de>
+ */
+
+#include <asm/assembly.h>
+#include <linux/linkage.h>
+
+       .section .text.hot
+       .level PA_ASM_LEVEL
+
+       t0 = r20
+       t1 = r21
+       t2 = r22
+
+ENTRY_CFI(strlen, frame=0,no_calls)
+       or,COND(<>) arg0,r0,ret0
+       b,l,n   .Lstrlen_null_ptr,r0
+       depwi   0,31,2,ret0
+       cmpb,COND(<>) arg0,ret0,.Lstrlen_not_aligned
+       ldw,ma  4(ret0),t0
+       cmpib,tr 0,r0,.Lstrlen_loop
+       uxor,nbz r0,t0,r0
+.Lstrlen_not_aligned:
+       uaddcm  arg0,ret0,t1
+       shladd  t1,3,r0,t1
+       mtsar   t1
+       depwi   -1,%sar,32,t0
+       uxor,nbz r0,t0,r0
+.Lstrlen_loop:
+       b,l,n   .Lstrlen_end_loop,r0
+       ldw,ma  4(ret0),t0
+       cmpib,tr 0,r0,.Lstrlen_loop
+       uxor,nbz r0,t0,r0
+.Lstrlen_end_loop:
+       extrw,u,<> t0,7,8,r0
+       addib,tr,n -3,ret0,.Lstrlen_out
+       extrw,u,<> t0,15,8,r0
+       addib,tr,n -2,ret0,.Lstrlen_out
+       extrw,u,<> t0,23,8,r0
+       addi    -1,ret0,ret0
+.Lstrlen_out:
+       bv r0(rp)
+       uaddcm ret0,arg0,ret0
+.Lstrlen_null_ptr:
+       bv,n r0(rp)
+ENDPROC_CFI(strlen)
+
+
+ENTRY_CFI(strcpy, frame=0,no_calls)
+       ldb     0(arg1),t0
+       stb     t0,0(arg0)
+       ldo     0(arg0),ret0
+       ldo     1(arg1),t1
+       cmpb,=  r0,t0,2f
+       ldo     1(arg0),t2
+1:     ldb     0(t1),arg1
+       stb     arg1,0(t2)
+       ldo     1(t1),t1
+       cmpb,<> r0,arg1,1b
+       ldo     1(t2),t2
+2:     bv,n    r0(rp)
+ENDPROC_CFI(strcpy)
+
+
+ENTRY_CFI(strncpy, frame=0,no_calls)
+       ldb     0(arg1),t0
+       stb     t0,0(arg0)
+       ldo     1(arg1),t1
+       ldo     0(arg0),ret0
+       cmpb,=  r0,t0,2f
+       ldo     1(arg0),arg1
+1:     ldo     -1(arg2),arg2
+       cmpb,COND(=),n r0,arg2,2f
+       ldb     0(t1),arg0
+       stb     arg0,0(arg1)
+       ldo     1(t1),t1
+       cmpb,<> r0,arg0,1b
+       ldo     1(arg1),arg1
+2:     bv,n    r0(rp)
+ENDPROC_CFI(strncpy)
+
+
+ENTRY_CFI(strcat, frame=0,no_calls)
+       ldb     0(arg0),t0
+       cmpb,=  t0,r0,2f
+       ldo     0(arg0),ret0
+       ldo     1(arg0),arg0
+1:     ldb     0(arg0),t1
+       cmpb,<>,n r0,t1,1b
+       ldo     1(arg0),arg0
+2:     ldb     0(arg1),t2
+       stb     t2,0(arg0)
+       ldo     1(arg0),arg0
+       ldb     0(arg1),t0
+       cmpb,<> r0,t0,2b
+       ldo     1(arg1),arg1
+       bv,n    r0(rp)
+ENDPROC_CFI(strcat)
+
+
+ENTRY_CFI(memset, frame=0,no_calls)
+       copy    arg0,ret0
+       cmpb,COND(=) r0,arg0,4f
+       copy    arg0,t2
+       cmpb,COND(=) r0,arg2,4f
+       ldo     -1(arg2),arg3
+       subi    -1,arg3,t0
+       subi    0,t0,t1
+       cmpiclr,COND(>=) 0,t1,arg2
+       ldo     -1(t1),arg2
+       extru arg2,31,2,arg0
+2:     stb     arg1,0(t2)
+       ldo     1(t2),t2
+       addib,>= -1,arg0,2b
+       ldo     -1(arg3),arg3
+       cmpiclr,COND(<=) 4,arg2,r0
+       b,l,n   4f,r0
+#ifdef CONFIG_64BIT
+       depd,*  r0,63,2,arg2
+#else
+       depw    r0,31,2,arg2
+#endif
+       ldo     1(t2),t2
+3:     stb     arg1,-1(t2)
+       stb     arg1,0(t2)
+       stb     arg1,1(t2)
+       stb     arg1,2(t2)
+       addib,COND(>) -4,arg2,3b
+       ldo     4(t2),t2
+4:     bv,n    r0(rp)
+ENDPROC_CFI(memset)
+
+       .end
index 77f6ebf..891cd23 100644 (file)
@@ -121,7 +121,6 @@ config PPC
        select ARCH_32BIT_OFF_T if PPC32
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
-       select ARCH_HAS_DMA_MMAP_PGPROT
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_GCOV_PROFILE_ALL
@@ -512,6 +511,7 @@ config KEXEC_FILE
        select KEXEC_CORE
        select HAVE_IMA_KEXEC
        select BUILD_BIN2C
+       select KEXEC_ELF
        depends on PPC64
        depends on CRYPTO=y
        depends on CRYPTO_SHA256=y
index c345b79..403f7e1 100644 (file)
@@ -39,13 +39,11 @@ endif
 uname := $(shell uname -m)
 KBUILD_DEFCONFIG := $(if $(filter ppc%,$(uname)),$(uname),ppc64)_defconfig
 
-ifdef CONFIG_PPC64
 new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi)
 
 ifeq ($(new_nm),y)
 NM             := $(NM) --synthetic
 endif
-endif
 
 # BITS is used as extension for files which are available in a 32 bit
 # and a 64 bit version to simplify shared Makefiles.
diff --git a/arch/powerpc/include/asm/error-injection.h b/arch/powerpc/include/asm/error-injection.h
deleted file mode 100644 (file)
index 62fd247..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-
-#ifndef _ASM_ERROR_INJECTION_H
-#define _ASM_ERROR_INJECTION_H
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm-generic/error-injection.h>
-
-void override_function_with_return(struct pt_regs *regs);
-
-#endif /* _ASM_ERROR_INJECTION_H */
index ea0c692..56dfa7a 100644 (file)
@@ -49,8 +49,7 @@ obj-y                         := cputable.o ptrace.o syscalls.o \
                                   signal.o sysfs.o cacheinfo.o time.o \
                                   prom.o traps.o setup-common.o \
                                   udbg.o misc.o io.o misc_$(BITS).o \
-                                  of_platform.o prom_parse.o \
-                                  dma-common.o
+                                  of_platform.o prom_parse.o
 obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
                                   paca.o nvram_64.o firmware.o
diff --git a/arch/powerpc/kernel/dma-common.c b/arch/powerpc/kernel/dma-common.c
deleted file mode 100644 (file)
index dc7ef6b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Contains common dma routines for all powerpc platforms.
- *
- * Copyright (C) 2019 Shawn Anastasio.
- */
-
-#include <linux/mm.h>
-#include <linux/dma-noncoherent.h>
-
-pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
-               unsigned long attrs)
-{
-       if (!dev_is_dma_coherent(dev))
-               return pgprot_noncached(prot);
-       return prot;
-}
index 83cf7b8..3072fd6 100644 (file)
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define PURGATORY_STACK_SIZE   (16 * 1024)
-
-#define elf_addr_to_cpu        elf64_to_cpu
-
-#ifndef Elf_Rel
-#define Elf_Rel                Elf64_Rel
-#endif /* Elf_Rel */
-
-struct elf_info {
-       /*
-        * Where the ELF binary contents are kept.
-        * Memory managed by the user of the struct.
-        */
-       const char *buffer;
-
-       const struct elfhdr *ehdr;
-       const struct elf_phdr *proghdrs;
-       struct elf_shdr *sechdrs;
-};
-
-static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
-{
-       return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
-}
-
-static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value)
-{
-       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-               value = le64_to_cpu(value);
-       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-               value = be64_to_cpu(value);
-
-       return value;
-}
-
-static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value)
-{
-       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-               value = le16_to_cpu(value);
-       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-               value = be16_to_cpu(value);
-
-       return value;
-}
-
-static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value)
-{
-       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-               value = le32_to_cpu(value);
-       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-               value = be32_to_cpu(value);
-
-       return value;
-}
-
-/**
- * elf_is_ehdr_sane - check that it is safe to use the ELF header
- * @buf_len:   size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len)
-{
-       if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) {
-               pr_debug("Bad program header size.\n");
-               return false;
-       } else if (ehdr->e_shnum > 0 &&
-                  ehdr->e_shentsize != sizeof(struct elf_shdr)) {
-               pr_debug("Bad section header size.\n");
-               return false;
-       } else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
-                  ehdr->e_version != EV_CURRENT) {
-               pr_debug("Unknown ELF version.\n");
-               return false;
-       }
-
-       if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
-               size_t phdr_size;
-
-               /*
-                * e_phnum is at most 65535 so calculating the size of the
-                * program header cannot overflow.
-                */
-               phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
-
-               /* Sanity check the program header table location. */
-               if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) {
-                       pr_debug("Program headers at invalid location.\n");
-                       return false;
-               } else if (ehdr->e_phoff + phdr_size > buf_len) {
-                       pr_debug("Program headers truncated.\n");
-                       return false;
-               }
-       }
-
-       if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
-               size_t shdr_size;
-
-               /*
-                * e_shnum is at most 65536 so calculating
-                * the size of the section header cannot overflow.
-                */
-               shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum;
-
-               /* Sanity check the section header table location. */
-               if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) {
-                       pr_debug("Section headers at invalid location.\n");
-                       return false;
-               } else if (ehdr->e_shoff + shdr_size > buf_len) {
-                       pr_debug("Section headers truncated.\n");
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
-{
-       struct elfhdr *buf_ehdr;
-
-       if (len < sizeof(*buf_ehdr)) {
-               pr_debug("Buffer is too small to hold ELF header.\n");
-               return -ENOEXEC;
-       }
-
-       memset(ehdr, 0, sizeof(*ehdr));
-       memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident));
-       if (!elf_is_elf_file(ehdr)) {
-               pr_debug("No ELF header magic.\n");
-               return -ENOEXEC;
-       }
-
-       if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
-               pr_debug("Not a supported ELF class.\n");
-               return -ENOEXEC;
-       } else  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
-               ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
-               pr_debug("Not a supported ELF data format.\n");
-               return -ENOEXEC;
-       }
-
-       buf_ehdr = (struct elfhdr *) buf;
-       if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) {
-               pr_debug("Bad ELF header size.\n");
-               return -ENOEXEC;
-       }
-
-       ehdr->e_type      = elf16_to_cpu(ehdr, buf_ehdr->e_type);
-       ehdr->e_machine   = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
-       ehdr->e_version   = elf32_to_cpu(ehdr, buf_ehdr->e_version);
-       ehdr->e_entry     = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry);
-       ehdr->e_phoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff);
-       ehdr->e_shoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff);
-       ehdr->e_flags     = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
-       ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
-       ehdr->e_phnum     = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
-       ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize);
-       ehdr->e_shnum     = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
-       ehdr->e_shstrndx  = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
-
-       return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_is_phdr_sane - check that it is safe to use the program header
- * @buf_len:   size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len)
-{
-
-       if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) {
-               pr_debug("ELF segment location wraps around.\n");
-               return false;
-       } else if (phdr->p_offset + phdr->p_filesz > buf_len) {
-               pr_debug("ELF segment not in file.\n");
-               return false;
-       } else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) {
-               pr_debug("ELF segment address wraps around.\n");
-               return false;
-       }
-
-       return true;
-}
-
-static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info,
-                        int idx)
-{
-       /* Override the const in proghdrs, we are the ones doing the loading. */
-       struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
-       const char *pbuf;
-       struct elf_phdr *buf_phdr;
-
-       pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr));
-       buf_phdr = (struct elf_phdr *) pbuf;
-
-       phdr->p_type   = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
-       phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset);
-       phdr->p_paddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr);
-       phdr->p_vaddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr);
-       phdr->p_flags  = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
-
-       /*
-        * The following fields have a type equivalent to Elf_Addr
-        * both in 32 bit and 64 bit ELF.
-        */
-       phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
-       phdr->p_memsz  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
-       phdr->p_align  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
-
-       return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_read_phdrs - read the program headers from the buffer
- *
- * This function assumes that the program header table was checked for sanity.
- * Use elf_is_ehdr_sane() if it wasn't.
- */
-static int elf_read_phdrs(const char *buf, size_t len,
-                         struct elf_info *elf_info)
-{
-       size_t phdr_size, i;
-       const struct elfhdr *ehdr = elf_info->ehdr;
-
-       /*
-        * e_phnum is at most 65535 so calculating the size of the
-        * program header cannot overflow.
-        */
-       phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
-
-       elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL);
-       if (!elf_info->proghdrs)
-               return -ENOMEM;
-
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               int ret;
-
-               ret = elf_read_phdr(buf, len, elf_info, i);
-               if (ret) {
-                       kfree(elf_info->proghdrs);
-                       elf_info->proghdrs = NULL;
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * elf_is_shdr_sane - check that it is safe to use the section header
- * @buf_len:   size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len)
-{
-       bool size_ok;
-
-       /* SHT_NULL headers have undefined values, so we can't check them. */
-       if (shdr->sh_type == SHT_NULL)
-               return true;
-
-       /* Now verify sh_entsize */
-       switch (shdr->sh_type) {
-       case SHT_SYMTAB:
-               size_ok = shdr->sh_entsize == sizeof(Elf_Sym);
-               break;
-       case SHT_RELA:
-               size_ok = shdr->sh_entsize == sizeof(Elf_Rela);
-               break;
-       case SHT_DYNAMIC:
-               size_ok = shdr->sh_entsize == sizeof(Elf_Dyn);
-               break;
-       case SHT_REL:
-               size_ok = shdr->sh_entsize == sizeof(Elf_Rel);
-               break;
-       case SHT_NOTE:
-       case SHT_PROGBITS:
-       case SHT_HASH:
-       case SHT_NOBITS:
-       default:
-               /*
-                * This is a section whose entsize requirements
-                * I don't care about.  If I don't know about
-                * the section I can't care about it's entsize
-                * requirements.
-                */
-               size_ok = true;
-               break;
-       }
-
-       if (!size_ok) {
-               pr_debug("ELF section with wrong entry size.\n");
-               return false;
-       } else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) {
-               pr_debug("ELF section address wraps around.\n");
-               return false;
-       }
-
-       if (shdr->sh_type != SHT_NOBITS) {
-               if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) {
-                       pr_debug("ELF section location wraps around.\n");
-                       return false;
-               } else if (shdr->sh_offset + shdr->sh_size > buf_len) {
-                       pr_debug("ELF section not in file.\n");
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info,
-                        int idx)
-{
-       struct elf_shdr *shdr = &elf_info->sechdrs[idx];
-       const struct elfhdr *ehdr = elf_info->ehdr;
-       const char *sbuf;
-       struct elf_shdr *buf_shdr;
-
-       sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr);
-       buf_shdr = (struct elf_shdr *) sbuf;
-
-       shdr->sh_name      = elf32_to_cpu(ehdr, buf_shdr->sh_name);
-       shdr->sh_type      = elf32_to_cpu(ehdr, buf_shdr->sh_type);
-       shdr->sh_addr      = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr);
-       shdr->sh_offset    = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset);
-       shdr->sh_link      = elf32_to_cpu(ehdr, buf_shdr->sh_link);
-       shdr->sh_info      = elf32_to_cpu(ehdr, buf_shdr->sh_info);
-
-       /*
-        * The following fields have a type equivalent to Elf_Addr
-        * both in 32 bit and 64 bit ELF.
-        */
-       shdr->sh_flags     = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags);
-       shdr->sh_size      = elf_addr_to_cpu(ehdr, buf_shdr->sh_size);
-       shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign);
-       shdr->sh_entsize   = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize);
-
-       return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_read_shdrs - read the section headers from the buffer
- *
- * This function assumes that the section header table was checked for sanity.
- * Use elf_is_ehdr_sane() if it wasn't.
- */
-static int elf_read_shdrs(const char *buf, size_t len,
-                         struct elf_info *elf_info)
-{
-       size_t shdr_size, i;
-
-       /*
-        * e_shnum is at most 65536 so calculating
-        * the size of the section header cannot overflow.
-        */
-       shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum;
-
-       elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL);
-       if (!elf_info->sechdrs)
-               return -ENOMEM;
-
-       for (i = 0; i < elf_info->ehdr->e_shnum; i++) {
-               int ret;
-
-               ret = elf_read_shdr(buf, len, elf_info, i);
-               if (ret) {
-                       kfree(elf_info->sechdrs);
-                       elf_info->sechdrs = NULL;
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info
- * @buf:       Buffer to read ELF file from.
- * @len:       Size of @buf.
- * @ehdr:      Pointer to existing struct which will be populated.
- * @elf_info:  Pointer to existing struct which will be populated.
- *
- * This function allows reading ELF files with different byte order than
- * the kernel, byte-swapping the fields as needed.
- *
- * Return:
- * On success returns 0, and the caller should call elf_free_info(elf_info) to
- * free the memory allocated for the section and program headers.
- */
-int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr,
-                        struct elf_info *elf_info)
-{
-       int ret;
-
-       ret = elf_read_ehdr(buf, len, ehdr);
-       if (ret)
-               return ret;
-
-       elf_info->buffer = buf;
-       elf_info->ehdr = ehdr;
-       if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
-               ret = elf_read_phdrs(buf, len, elf_info);
-               if (ret)
-                       return ret;
-       }
-       if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
-               ret = elf_read_shdrs(buf, len, elf_info);
-               if (ret) {
-                       kfree(elf_info->proghdrs);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * elf_free_info - free memory allocated by elf_read_from_buffer
- */
-void elf_free_info(struct elf_info *elf_info)
-{
-       kfree(elf_info->proghdrs);
-       kfree(elf_info->sechdrs);
-       memset(elf_info, 0, sizeof(*elf_info));
-}
-/**
- * build_elf_exec_info - read ELF executable and check that we can use it
- */
-static int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr,
-                              struct elf_info *elf_info)
-{
-       int i;
-       int ret;
-
-       ret = elf_read_from_buffer(buf, len, ehdr, elf_info);
-       if (ret)
-               return ret;
-
-       /* Big endian vmlinux has type ET_DYN. */
-       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
-               pr_err("Not an ELF executable.\n");
-               goto error;
-       } else if (!elf_info->proghdrs) {
-               pr_err("No ELF program header.\n");
-               goto error;
-       }
-
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               /*
-                * Kexec does not support loading interpreters.
-                * In addition this check keeps us from attempting
-                * to kexec ordinay executables.
-                */
-               if (elf_info->proghdrs[i].p_type == PT_INTERP) {
-                       pr_err("Requires an ELF interpreter.\n");
-                       goto error;
-               }
-       }
-
-       return 0;
-error:
-       elf_free_info(elf_info);
-       return -ENOEXEC;
-}
-
-static int elf64_probe(const char *buf, unsigned long len)
-{
-       struct elfhdr ehdr;
-       struct elf_info elf_info;
-       int ret;
-
-       ret = build_elf_exec_info(buf, len, &ehdr, &elf_info);
-       if (ret)
-               return ret;
-
-       elf_free_info(&elf_info);
-
-       return elf_check_arch(&ehdr) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_exec_load - load ELF executable image
- * @lowest_load_addr:  On return, will be the address where the first PT_LOAD
- *                     section will be loaded in memory.
- *
- * Return:
- * 0 on success, negative value on failure.
- */
-static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
-                        struct elf_info *elf_info,
-                        unsigned long *lowest_load_addr)
-{
-       unsigned long base = 0, lowest_addr = UINT_MAX;
-       int ret;
-       size_t i;
-       struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size,
-                                 .top_down = false };
-
-       /* Read in the PT_LOAD segments. */
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               unsigned long load_addr;
-               size_t size;
-               const struct elf_phdr *phdr;
-
-               phdr = &elf_info->proghdrs[i];
-               if (phdr->p_type != PT_LOAD)
-                       continue;
-
-               size = phdr->p_filesz;
-               if (size > phdr->p_memsz)
-                       size = phdr->p_memsz;
-
-               kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
-               kbuf.bufsz = size;
-               kbuf.memsz = phdr->p_memsz;
-               kbuf.buf_align = phdr->p_align;
-               kbuf.buf_min = phdr->p_paddr + base;
-               kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
-               ret = kexec_add_buffer(&kbuf);
-               if (ret)
-                       goto out;
-               load_addr = kbuf.mem;
-
-               if (load_addr < lowest_addr)
-                       lowest_addr = load_addr;
-       }
-
-       /* Update entry point to reflect new load address. */
-       ehdr->e_entry += base;
-
-       *lowest_load_addr = lowest_addr;
-       ret = 0;
- out:
-       return ret;
-}
-
 static void *elf64_load(struct kimage *image, char *kernel_buf,
                        unsigned long kernel_len, char *initrd,
                        unsigned long initrd_len, char *cmdline,
@@ -570,18 +35,18 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
        void *fdt;
        const void *slave_code;
        struct elfhdr ehdr;
-       struct elf_info elf_info;
+       struct kexec_elf_info elf_info;
        struct kexec_buf kbuf = { .image = image, .buf_min = 0,
                                  .buf_max = ppc64_rma_size };
        struct kexec_buf pbuf = { .image = image, .buf_min = 0,
                                  .buf_max = ppc64_rma_size, .top_down = true,
                                  .mem = KEXEC_BUF_MEM_UNKNOWN };
 
-       ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+       ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
        if (ret)
                goto out;
 
-       ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr);
+       ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
        if (ret)
                goto out;
 
@@ -648,13 +113,13 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
                pr_err("Error setting up the purgatory.\n");
 
 out:
-       elf_free_info(&elf_info);
+       kexec_free_elf_info(&elf_info);
 
        /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */
        return ret ? ERR_PTR(ret) : fdt;
 }
 
 const struct kexec_file_ops kexec_elf64_ops = {
-       .probe = elf64_probe,
+       .probe = kexec_elf_probe,
        .load = elf64_load,
 };
index 8fc4de0..7a84c9f 100644 (file)
@@ -101,21 +101,8 @@ static void check_if_tm_restore_required(struct task_struct *tsk)
        }
 }
 
-static bool tm_active_with_fp(struct task_struct *tsk)
-{
-       return MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
-               (tsk->thread.ckpt_regs.msr & MSR_FP);
-}
-
-static bool tm_active_with_altivec(struct task_struct *tsk)
-{
-       return MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
-               (tsk->thread.ckpt_regs.msr & MSR_VEC);
-}
 #else
 static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
-static inline bool tm_active_with_fp(struct task_struct *tsk) { return false; }
-static inline bool tm_active_with_altivec(struct task_struct *tsk) { return false; }
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
 bool strict_msr_control;
@@ -252,7 +239,7 @@ EXPORT_SYMBOL(enable_kernel_fp);
 
 static int restore_fp(struct task_struct *tsk)
 {
-       if (tsk->thread.load_fp || tm_active_with_fp(tsk)) {
+       if (tsk->thread.load_fp) {
                load_fp_state(&current->thread.fp_state);
                current->thread.load_fp++;
                return 1;
@@ -334,8 +321,7 @@ EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
 
 static int restore_altivec(struct task_struct *tsk)
 {
-       if (cpu_has_feature(CPU_FTR_ALTIVEC) &&
-               (tsk->thread.load_vec || tm_active_with_altivec(tsk))) {
+       if (cpu_has_feature(CPU_FTR_ALTIVEC) && (tsk->thread.load_vec)) {
                load_vr_state(&tsk->thread.vr_state);
                tsk->thread.used_vr = 1;
                tsk->thread.load_vec++;
@@ -497,13 +483,14 @@ void giveup_all(struct task_struct *tsk)
        if (!tsk->thread.regs)
                return;
 
+       check_if_tm_restore_required(tsk);
+
        usermsr = tsk->thread.regs->msr;
 
        if ((usermsr & msr_all_available) == 0)
                return;
 
        msr_check_and_set(msr_all_available);
-       check_if_tm_restore_required(tsk);
 
        WARN_ON((usermsr & MSR_VSX) && !((usermsr & MSR_FP) && (usermsr & MSR_VEC)));
 
index e99a147..c4b606f 100644 (file)
@@ -660,8 +660,10 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                }
                tce = be64_to_cpu(tce);
 
-               if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua))
-                       return H_PARAMETER;
+               if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua)) {
+                       ret = H_PARAMETER;
+                       goto unlock_exit;
+               }
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
                        ret = kvmppc_tce_iommu_map(vcpu->kvm, stt,
index f50bbee..b4f20f1 100644 (file)
@@ -556,8 +556,10 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                unsigned long tce = be64_to_cpu(((u64 *)tces)[i]);
 
                ua = 0;
-               if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua, NULL))
-                       return H_PARAMETER;
+               if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua, NULL)) {
+                       ret = H_PARAMETER;
+                       goto unlock_exit;
+               }
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
                        ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
index d4acf6f..bf60983 100644 (file)
@@ -630,7 +630,6 @@ static void early_init_this_mmu(void)
 #ifdef CONFIG_PPC_FSL_BOOK3E
        if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
                unsigned int num_cams;
-               int __maybe_unused cpu = smp_processor_id();
                bool map = true;
 
                /* use a quarter of the TLBCAM for bolted linear map */
diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild
new file mode 100644 (file)
index 0000000..d1d0aa7
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += kernel/ mm/ net/
index 59a4727..1211543 100644 (file)
@@ -35,6 +35,8 @@ config RISCV
        select HAVE_DMA_CONTIGUOUS
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_PERF_EVENTS
+       select HAVE_PERF_REGS
+       select HAVE_PERF_USER_STACK_DUMP
        select HAVE_SYSCALL_TRACEPOINTS
        select IRQ_DOMAIN
        select SPARSE_IRQ
@@ -48,12 +50,14 @@ config RISCV
        select PCI_MSI if PCI
        select RISCV_TIMER
        select GENERIC_IRQ_MULTI_HANDLER
+       select GENERIC_ARCH_TOPOLOGY if SMP
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_MMIOWB
        select HAVE_EBPF_JIT if 64BIT
        select EDAC_SUPPORT
        select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
+       select SPARSEMEM_STATIC if 32BIT
 
 config MMU
        def_bool y
@@ -62,12 +66,32 @@ config ZONE_DMA32
        bool
        default y if 64BIT
 
+config VA_BITS
+       int
+       default 32 if 32BIT
+       default 39 if 64BIT
+
+config PA_BITS
+       int
+       default 34 if 32BIT
+       default 56 if 64BIT
+
 config PAGE_OFFSET
        hex
        default 0xC0000000 if 32BIT && MAXPHYSMEM_2GB
        default 0xffffffff80000000 if 64BIT && MAXPHYSMEM_2GB
        default 0xffffffe000000000 if 64BIT && MAXPHYSMEM_128GB
 
+config ARCH_FLATMEM_ENABLE
+       def_bool y
+
+config ARCH_SPARSEMEM_ENABLE
+       def_bool y
+       select SPARSEMEM_VMEMMAP_ENABLE
+
+config ARCH_SELECT_MEMORY_MODEL
+       def_bool ARCH_SPARSEMEM_ENABLE
+
 config ARCH_WANT_GENERAL_HUGETLB
        def_bool y
 
index 7a117be..4f0a3d2 100644 (file)
@@ -54,6 +54,9 @@ endif
 ifeq ($(CONFIG_MODULE_SECTIONS),y)
        KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/riscv/kernel/module.lds
 endif
+ifeq ($(CONFIG_PERF_EVENTS),y)
+        KBUILD_CFLAGS += -fno-omit-frame-pointer
+endif
 
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
 
@@ -72,7 +75,7 @@ KBUILD_IMAGE  := $(boot)/Image.gz
 
 head-y := arch/riscv/kernel/head.o
 
-core-y += arch/riscv/kernel/ arch/riscv/mm/ arch/riscv/net/
+core-y += arch/riscv/
 
 libs-y += arch/riscv/lib/
 
index 93205c0..3efff55 100644 (file)
@@ -54,6 +54,8 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
 CONFIG_HVC_RISCV_SBI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
index d5449ef..7da93e4 100644 (file)
@@ -34,6 +34,7 @@ CONFIG_PCIEPORTBUS=y
 CONFIG_PCI_HOST_GENERIC=y
 CONFIG_PCIE_XILINX=y
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_SD=y
@@ -53,6 +54,8 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
 CONFIG_HVC_RISCV_SBI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
index 9c66033..161f28d 100644 (file)
@@ -30,10 +30,6 @@ enum fixed_addresses {
        __end_of_fixed_addresses
 };
 
-#define FIXADDR_SIZE           (__end_of_fixed_addresses * PAGE_SIZE)
-#define FIXADDR_TOP            (VMALLOC_START)
-#define FIXADDR_START          (FIXADDR_TOP - FIXADDR_SIZE)
-
 #define FIXMAP_PAGE_IO         PAGE_KERNEL
 
 #define __early_set_fixmap     __set_fixmap
index ef28e10..344db52 100644 (file)
@@ -3,7 +3,8 @@
 #ifndef __ASM_IMAGE_H
 #define __ASM_IMAGE_H
 
-#define RISCV_IMAGE_MAGIC      "RISCV"
+#define RISCV_IMAGE_MAGIC      "RISCV\0\0\0"
+#define RISCV_IMAGE_MAGIC2     "RSC\x05"
 
 #define RISCV_IMAGE_FLAG_BE_SHIFT      0
 #define RISCV_IMAGE_FLAG_BE_MASK       0x1
@@ -23,7 +24,7 @@
 #define __HEAD_FLAGS           (__HEAD_FLAG(BE))
 
 #define RISCV_HEADER_VERSION_MAJOR 0
-#define RISCV_HEADER_VERSION_MINOR 1
+#define RISCV_HEADER_VERSION_MINOR 2
 
 #define RISCV_HEADER_VERSION (RISCV_HEADER_VERSION_MAJOR << 16 | \
                              RISCV_HEADER_VERSION_MINOR)
@@ -39,9 +40,8 @@
  * @version:           version
  * @res1:              reserved
  * @res2:              reserved
- * @magic:             Magic number
- * @res3:              reserved (will be used for additional RISC-V specific
- *                     header)
+ * @magic:             Magic number (RISC-V specific; deprecated)
+ * @magic2:            Magic number 2 (to match the ARM64 'magic' field pos)
  * @res4:              reserved (will be used for PE COFF offset)
  *
  * The intention is for this header format to be shared between multiple
@@ -58,7 +58,7 @@ struct riscv_image_header {
        u32 res1;
        u64 res2;
        u64 magic;
-       u32 res3;
+       u32 magic2;
        u32 res4;
 };
 #endif /* __ASSEMBLY__ */
index 707e00a..3db261c 100644 (file)
@@ -110,8 +110,10 @@ extern unsigned long min_low_pfn;
 #define page_to_bus(page)      (page_to_phys(page))
 #define phys_to_page(paddr)    (pfn_to_page(phys_to_pfn(paddr)))
 
+#ifdef CONFIG_FLATMEM
 #define pfn_valid(pfn) \
        (((pfn) >= pfn_base) && (((pfn)-pfn_base) < max_mapnr))
+#endif
 
 #define ARCH_PFN_OFFSET                (pfn_base)
 
index a364aba..80905b2 100644 (file)
@@ -83,6 +83,19 @@ extern pgd_t swapper_pg_dir[];
 #define __S110 PAGE_SHARED_EXEC
 #define __S111 PAGE_SHARED_EXEC
 
+/*
+ * Roughly size the vmemmap space to be large enough to fit enough
+ * struct pages to map half the virtual address space. Then
+ * position vmemmap directly below the VMALLOC region.
+ */
+#define VMEMMAP_SHIFT \
+       (CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
+#define VMEMMAP_SIZE   BIT(VMEMMAP_SHIFT)
+#define VMEMMAP_END    (VMALLOC_START - 1)
+#define VMEMMAP_START  (VMALLOC_START - VMEMMAP_SIZE)
+
+#define vmemmap                ((struct page *)VMEMMAP_START)
+
 /*
  * ZERO_PAGE is a global shared page that is always zero,
  * used for zero-mapped memory areas, etc.
@@ -420,14 +433,22 @@ static inline void pgtable_cache_init(void)
 #define VMALLOC_END      (PAGE_OFFSET - 1)
 #define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE)
 
+#define FIXADDR_TOP      VMALLOC_START
+#ifdef CONFIG_64BIT
+#define FIXADDR_SIZE     PMD_SIZE
+#else
+#define FIXADDR_SIZE     PGDIR_SIZE
+#endif
+#define FIXADDR_START    (FIXADDR_TOP - FIXADDR_SIZE)
+
 /*
- * Task size is 0x4000000000 for RV64 or 0xb800000 for RV32.
+ * Task size is 0x4000000000 for RV64 or 0x9fc00000 for RV32.
  * Note that PGDIR_SIZE must evenly divide TASK_SIZE.
  */
 #ifdef CONFIG_64BIT
 #define TASK_SIZE (PGDIR_SIZE * PTRS_PER_PGD / 2)
 #else
-#define TASK_SIZE VMALLOC_START
+#define TASK_SIZE FIXADDR_START
 #endif
 
 #include <asm-generic/pgtable.h>
index c6ed4d6..a83451d 100644 (file)
@@ -61,11 +61,5 @@ static inline unsigned long cpuid_to_hartid_map(int cpu)
        return boot_cpu_hartid;
 }
 
-static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
-                                             struct cpumask *out)
-{
-       cpumask_set_cpu(cpuid_to_hartid_map(0), out);
-}
-
 #endif /* CONFIG_SMP */
 #endif /* _ASM_RISCV_SMP_H */
diff --git a/arch/riscv/include/asm/sparsemem.h b/arch/riscv/include/asm/sparsemem.h
new file mode 100644 (file)
index 0000000..b58ba2d
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_SPARSEMEM_H
+#define __ASM_SPARSEMEM_H
+
+#ifdef CONFIG_SPARSEMEM
+#define MAX_PHYSMEM_BITS       CONFIG_PA_BITS
+#define SECTION_SIZE_BITS      27
+#endif /* CONFIG_SPARSEMEM */
+
+#endif /* __ASM_SPARSEMEM_H */
index 853b65e..f0227bd 100644 (file)
@@ -16,7 +16,13 @@ extern void __fstate_restore(struct task_struct *restore_from);
 
 static inline void __fstate_clean(struct pt_regs *regs)
 {
-       regs->sstatus |= (regs->sstatus & ~(SR_FS)) | SR_FS_CLEAN;
+       regs->sstatus = (regs->sstatus & ~SR_FS) | SR_FS_CLEAN;
+}
+
+static inline void fstate_off(struct task_struct *task,
+                             struct pt_regs *regs)
+{
+       regs->sstatus = (regs->sstatus & ~SR_FS) | SR_FS_OFF;
 }
 
 static inline void fstate_save(struct task_struct *task,
index 6a703ec..c7ef131 100644 (file)
@@ -6,43 +6,41 @@
 #ifndef _ASM_RISCV_TIMEX_H
 #define _ASM_RISCV_TIMEX_H
 
-#include <asm/param.h>
+#include <asm/csr.h>
 
 typedef unsigned long cycles_t;
 
-static inline cycles_t get_cycles_inline(void)
+static inline cycles_t get_cycles(void)
 {
-       cycles_t n;
-
-       __asm__ __volatile__ (
-               "rdtime %0"
-               : "=r" (n));
-       return n;
+       return csr_read(CSR_TIME);
 }
-#define get_cycles get_cycles_inline
+#define get_cycles get_cycles
 
 #ifdef CONFIG_64BIT
-static inline uint64_t get_cycles64(void)
+static inline u64 get_cycles64(void)
+{
+       return get_cycles();
+}
+#else /* CONFIG_64BIT */
+static inline u32 get_cycles_hi(void)
 {
-        return get_cycles();
+       return csr_read(CSR_TIMEH);
 }
-#else
-static inline uint64_t get_cycles64(void)
+
+static inline u64 get_cycles64(void)
 {
-       u32 lo, hi, tmp;
-       __asm__ __volatile__ (
-               "1:\n"
-               "rdtimeh %0\n"
-               "rdtime %1\n"
-               "rdtimeh %2\n"
-               "bne %0, %2, 1b"
-               : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+       u32 hi, lo;
+
+       do {
+               hi = get_cycles_hi();
+               lo = get_cycles();
+       } while (hi != get_cycles_hi());
+
        return ((u64)hi << 32) | lo;
 }
-#endif
+#endif /* CONFIG_64BIT */
 
 #define ARCH_HAS_READ_CURRENT_TIMER
-
 static inline int read_current_timer(unsigned long *timer_val)
 {
        *timer_val = get_cycles();
index 687dd19..37ae4e3 100644 (file)
@@ -25,8 +25,13 @@ static inline void local_flush_tlb_page(unsigned long addr)
        __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");
 }
 
-#ifndef CONFIG_SMP
-
+#ifdef CONFIG_SMP
+void flush_tlb_all(void);
+void flush_tlb_mm(struct mm_struct *mm);
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                    unsigned long end);
+#else /* CONFIG_SMP */
 #define flush_tlb_all() local_flush_tlb_all()
 #define flush_tlb_page(vma, addr) local_flush_tlb_page(addr)
 
@@ -37,28 +42,6 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 }
 
 #define flush_tlb_mm(mm) flush_tlb_all()
-
-#else /* CONFIG_SMP */
-
-#include <asm/sbi.h>
-
-static inline void remote_sfence_vma(struct cpumask *cmask, unsigned long start,
-                                    unsigned long size)
-{
-       struct cpumask hmask;
-
-       cpumask_clear(&hmask);
-       riscv_cpuid_to_hartid_mask(cmask, &hmask);
-       sbi_remote_sfence_vma(hmask.bits, start, size);
-}
-
-#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1)
-#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0)
-#define flush_tlb_range(vma, start, end) \
-       remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start))
-#define flush_tlb_mm(mm) \
-       remote_sfence_vma(mm_cpumask(mm), 0, -1)
-
 #endif /* CONFIG_SMP */
 
 /* Flush a range of kernel pages */
diff --git a/arch/riscv/include/uapi/asm/perf_regs.h b/arch/riscv/include/uapi/asm/perf_regs.h
new file mode 100644 (file)
index 0000000..196f964
--- /dev/null
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#ifndef _ASM_RISCV_PERF_REGS_H
+#define _ASM_RISCV_PERF_REGS_H
+
+enum perf_event_riscv_regs {
+       PERF_REG_RISCV_PC,
+       PERF_REG_RISCV_RA,
+       PERF_REG_RISCV_SP,
+       PERF_REG_RISCV_GP,
+       PERF_REG_RISCV_TP,
+       PERF_REG_RISCV_T0,
+       PERF_REG_RISCV_T1,
+       PERF_REG_RISCV_T2,
+       PERF_REG_RISCV_S0,
+       PERF_REG_RISCV_S1,
+       PERF_REG_RISCV_A0,
+       PERF_REG_RISCV_A1,
+       PERF_REG_RISCV_A2,
+       PERF_REG_RISCV_A3,
+       PERF_REG_RISCV_A4,
+       PERF_REG_RISCV_A5,
+       PERF_REG_RISCV_A6,
+       PERF_REG_RISCV_A7,
+       PERF_REG_RISCV_S2,
+       PERF_REG_RISCV_S3,
+       PERF_REG_RISCV_S4,
+       PERF_REG_RISCV_S5,
+       PERF_REG_RISCV_S6,
+       PERF_REG_RISCV_S7,
+       PERF_REG_RISCV_S8,
+       PERF_REG_RISCV_S9,
+       PERF_REG_RISCV_S10,
+       PERF_REG_RISCV_S11,
+       PERF_REG_RISCV_T3,
+       PERF_REG_RISCV_T4,
+       PERF_REG_RISCV_T5,
+       PERF_REG_RISCV_T6,
+       PERF_REG_RISCV_MAX,
+};
+#endif /* _ASM_RISCV_PERF_REGS_H */
index 2420d37..696020f 100644 (file)
@@ -38,6 +38,8 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += mcount-dyn.o
 
-obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
+obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
+obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
+obj-$(CONFIG_HAVE_PERF_REGS)   += perf_regs.o
 
 clean:
index bc7a56e..74ccfd4 100644 (file)
@@ -167,7 +167,7 @@ ENTRY(handle_exception)
        tail do_IRQ
 1:
        /* Exceptions run with interrupts enabled */
-       csrs sstatus, SR_SIE
+       csrs CSR_SSTATUS, SR_SIE
 
        /* Handle syscalls */
        li t0, EXC_SYSCALL
@@ -222,7 +222,7 @@ ret_from_syscall:
 
 ret_from_exception:
        REG_L s0, PT_SSTATUS(sp)
-       csrc sstatus, SR_SIE
+       csrc CSR_SSTATUS, SR_SIE
        andi s0, s0, SR_SPP
        bnez s0, resume_kernel
 
@@ -265,7 +265,7 @@ work_pending:
        bnez s1, work_resched
 work_notifysig:
        /* Handle pending signals and notify-resume requests */
-       csrs sstatus, SR_SIE /* Enable interrupts for do_notify_resume() */
+       csrs CSR_SSTATUS, SR_SIE /* Enable interrupts for do_notify_resume() */
        move a0, sp /* pt_regs */
        move a1, s0 /* current_thread_info->flags */
        tail do_notify_resume
index 1defb06..631d315 100644 (file)
@@ -23,7 +23,7 @@ ENTRY(__fstate_save)
        li  a2,  TASK_THREAD_F0
        add a0, a0, a2
        li t1, SR_FS
-       csrs sstatus, t1
+       csrs CSR_SSTATUS, t1
        frcsr t0
        fsd f0,  TASK_THREAD_F0_F0(a0)
        fsd f1,  TASK_THREAD_F1_F0(a0)
@@ -58,7 +58,7 @@ ENTRY(__fstate_save)
        fsd f30, TASK_THREAD_F30_F0(a0)
        fsd f31, TASK_THREAD_F31_F0(a0)
        sw t0, TASK_THREAD_FCSR_F0(a0)
-       csrc sstatus, t1
+       csrc CSR_SSTATUS, t1
        ret
 ENDPROC(__fstate_save)
 
@@ -67,7 +67,7 @@ ENTRY(__fstate_restore)
        add a0, a0, a2
        li t1, SR_FS
        lw t0, TASK_THREAD_FCSR_F0(a0)
-       csrs sstatus, t1
+       csrs CSR_SSTATUS, t1
        fld f0,  TASK_THREAD_F0_F0(a0)
        fld f1,  TASK_THREAD_F1_F0(a0)
        fld f2,  TASK_THREAD_F2_F0(a0)
@@ -101,6 +101,6 @@ ENTRY(__fstate_restore)
        fld f30, TASK_THREAD_F30_F0(a0)
        fld f31, TASK_THREAD_F31_F0(a0)
        fscsr t0
-       csrc sstatus, t1
+       csrc CSR_SSTATUS, t1
        ret
 ENDPROC(__fstate_restore)
index 0f1ba17..15a9189 100644 (file)
@@ -39,9 +39,9 @@ ENTRY(_start)
        .word RISCV_HEADER_VERSION
        .word 0
        .dword 0
-       .asciz RISCV_IMAGE_MAGIC
-       .word 0
+       .ascii RISCV_IMAGE_MAGIC
        .balign 4
+       .ascii RISCV_IMAGE_MAGIC2
        .word 0
 
 .global _start_kernel
@@ -61,7 +61,7 @@ _start_kernel:
         * floating point in kernel space
         */
        li t0, SR_FS
-       csrc sstatus, t0
+       csrc CSR_SSTATUS, t0
 
        /* Pick one hart to run the main boot sequence */
        la a3, hart_lottery
diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
new file mode 100644 (file)
index 0000000..8d2804f
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#include <linux/perf_event.h>
+#include <linux/uaccess.h>
+
+/* Kernel callchain */
+struct stackframe {
+       unsigned long fp;
+       unsigned long ra;
+};
+
+/*
+ * Get the return address for a single stackframe and return a pointer to the
+ * next frame tail.
+ */
+static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
+                                   unsigned long fp, unsigned long reg_ra)
+{
+       struct stackframe buftail;
+       unsigned long ra = 0;
+       unsigned long *user_frame_tail =
+                       (unsigned long *)(fp - sizeof(struct stackframe));
+
+       /* Check accessibility of one struct frame_tail beyond */
+       if (!access_ok(user_frame_tail, sizeof(buftail)))
+               return 0;
+       if (__copy_from_user_inatomic(&buftail, user_frame_tail,
+                                     sizeof(buftail)))
+               return 0;
+
+       if (reg_ra != 0)
+               ra = reg_ra;
+       else
+               ra = buftail.ra;
+
+       fp = buftail.fp;
+       if (ra != 0)
+               perf_callchain_store(entry, ra);
+       else
+               return 0;
+
+       return fp;
+}
+
+/*
+ * This will be called when the target is in user mode
+ * This function will only be called when we use
+ * "PERF_SAMPLE_CALLCHAIN" in
+ * kernel/events/core.c:perf_prepare_sample()
+ *
+ * How to trigger perf_callchain_[user/kernel] :
+ * $ perf record -e cpu-clock --call-graph fp ./program
+ * $ perf report --call-graph
+ *
+ * On RISC-V platform, the program being sampled and the C library
+ * need to be compiled with -fno-omit-frame-pointer, otherwise
+ * the user stack will not contain function frame.
+ */
+void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
+                        struct pt_regs *regs)
+{
+       unsigned long fp = 0;
+
+       /* RISC-V does not support perf in guest mode. */
+       if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+               return;
+
+       fp = regs->s0;
+       perf_callchain_store(entry, regs->sepc);
+
+       fp = user_backtrace(entry, fp, regs->ra);
+       while (fp && !(fp & 0x3) && entry->nr < entry->max_stack)
+               fp = user_backtrace(entry, fp, 0);
+}
+
+bool fill_callchain(unsigned long pc, void *entry)
+{
+       return perf_callchain_store(entry, pc);
+}
+
+void notrace walk_stackframe(struct task_struct *task,
+       struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg);
+void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
+                          struct pt_regs *regs)
+{
+       /* RISC-V does not support perf in guest mode. */
+       if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+               pr_warn("RISC-V does not support perf in guest mode!");
+               return;
+       }
+
+       walk_stackframe(NULL, regs, fill_callchain, entry);
+}
diff --git a/arch/riscv/kernel/perf_regs.c b/arch/riscv/kernel/perf_regs.c
new file mode 100644 (file)
index 0000000..04a38fb
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+       if (WARN_ON_ONCE((u32)idx >= PERF_REG_RISCV_MAX))
+               return 0;
+
+       return ((unsigned long *)regs)[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_RISCV_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+       if (!mask || mask & REG_RESERVED)
+               return -EINVAL;
+
+       return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+#if __riscv_xlen == 64
+       return PERF_SAMPLE_REGS_ABI_64;
+#else
+       return PERF_SAMPLE_REGS_ABI_32;
+#endif
+}
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}
index f23794b..fb3a082 100644 (file)
@@ -64,8 +64,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
        unsigned long sp)
 {
        regs->sstatus = SR_SPIE;
-       if (has_fpu)
+       if (has_fpu) {
                regs->sstatus |= SR_FS_INITIAL;
+               /*
+                * Restore the initial value to the FP register
+                * before starting the user program.
+                */
+               fstate_restore(current, regs);
+       }
        regs->sepc = pc;
        regs->sp = sp;
        set_fs(USER_DS);
@@ -75,10 +81,11 @@ void flush_thread(void)
 {
 #ifdef CONFIG_FPU
        /*
-        * Reset FPU context
+        * Reset FPU state and context
         *      frm: round to nearest, ties to even (IEEE default)
         *      fflags: accrued exceptions cleared
         */
+       fstate_off(current, task_pt_regs(current));
        memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
 #endif
 }
index 5a98345..3836760 100644 (file)
@@ -56,6 +56,7 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out)
 {
        int cpu;
 
+       cpumask_clear(out);
        for_each_cpu(cpu, in)
                cpumask_set_cpu(cpuid_to_hartid_map(cpu), out);
 }
@@ -78,13 +79,42 @@ static void ipi_stop(void)
                wait_for_interrupt();
 }
 
+static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
+{
+       struct cpumask hartid_mask;
+       int cpu;
+
+       smp_mb__before_atomic();
+       for_each_cpu(cpu, mask)
+               set_bit(op, &ipi_data[cpu].bits);
+       smp_mb__after_atomic();
+
+       riscv_cpuid_to_hartid_mask(mask, &hartid_mask);
+       sbi_send_ipi(cpumask_bits(&hartid_mask));
+}
+
+static void send_ipi_single(int cpu, enum ipi_message_type op)
+{
+       int hartid = cpuid_to_hartid_map(cpu);
+
+       smp_mb__before_atomic();
+       set_bit(op, &ipi_data[cpu].bits);
+       smp_mb__after_atomic();
+
+       sbi_send_ipi(cpumask_bits(cpumask_of(hartid)));
+}
+
+static inline void clear_ipi(void)
+{
+       csr_clear(CSR_SIP, SIE_SSIE);
+}
+
 void riscv_software_interrupt(void)
 {
        unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
        unsigned long *stats = ipi_data[smp_processor_id()].stats;
 
-       /* Clear pending IPI */
-       csr_clear(CSR_SIP, SIE_SSIE);
+       clear_ipi();
 
        while (true) {
                unsigned long ops;
@@ -118,23 +148,6 @@ void riscv_software_interrupt(void)
        }
 }
 
-static void
-send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
-{
-       int cpuid, hartid;
-       struct cpumask hartid_mask;
-
-       cpumask_clear(&hartid_mask);
-       mb();
-       for_each_cpu(cpuid, to_whom) {
-               set_bit(operation, &ipi_data[cpuid].bits);
-               hartid = cpuid_to_hartid_map(cpuid);
-               cpumask_set_cpu(hartid, &hartid_mask);
-       }
-       mb();
-       sbi_send_ipi(cpumask_bits(&hartid_mask));
-}
-
 static const char * const ipi_names[] = {
        [IPI_RESCHEDULE]        = "Rescheduling interrupts",
        [IPI_CALL_FUNC]         = "Function call interrupts",
@@ -156,12 +169,12 @@ void show_ipi_stats(struct seq_file *p, int prec)
 
 void arch_send_call_function_ipi_mask(struct cpumask *mask)
 {
-       send_ipi_message(mask, IPI_CALL_FUNC);
+       send_ipi_mask(mask, IPI_CALL_FUNC);
 }
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
+       send_ipi_single(cpu, IPI_CALL_FUNC);
 }
 
 void smp_send_stop(void)
@@ -176,7 +189,7 @@ void smp_send_stop(void)
 
                if (system_state <= SYSTEM_RUNNING)
                        pr_crit("SMP: stopping secondary CPUs\n");
-               send_ipi_message(&mask, IPI_CPU_STOP);
+               send_ipi_mask(&mask, IPI_CPU_STOP);
        }
 
        /* Wait up to one second for other CPUs to stop */
@@ -191,6 +204,5 @@ void smp_send_stop(void)
 
 void smp_send_reschedule(int cpu)
 {
-       send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
+       send_ipi_single(cpu, IPI_RESCHEDULE);
 }
-
index 7462a44..18ae6da 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 2017 SiFive
  */
 
+#include <linux/arch_topology.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -35,6 +36,7 @@ static DECLARE_COMPLETION(cpu_running);
 
 void __init smp_prepare_boot_cpu(void)
 {
+       init_cpu_topology();
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
@@ -138,6 +140,7 @@ asmlinkage void __init smp_callin(void)
 
        trap_init();
        notify_cpu_starting(smp_processor_id());
+       update_siblings_masks(smp_processor_id());
        set_cpu_online(smp_processor_id(), 1);
        /*
         * Remote TLB flushes are ignored while the CPU is offline, so emit
index f156427..0940681 100644 (file)
@@ -19,8 +19,8 @@ struct stackframe {
        unsigned long ra;
 };
 
-static void notrace walk_stackframe(struct task_struct *task,
-       struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
+void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
+                            bool (*fn)(unsigned long, void *), void *arg)
 {
        unsigned long fp, sp, pc;
 
index 399e6f0..ed2696c 100644 (file)
@@ -18,7 +18,7 @@ ENTRY(__asm_copy_from_user)
 
        /* Enable access to user memory */
        li t6, SR_SUM
-       csrs sstatus, t6
+       csrs CSR_SSTATUS, t6
 
        add a3, a1, a2
        /* Use word-oriented copy only if low-order bits match */
@@ -47,7 +47,7 @@ ENTRY(__asm_copy_from_user)
 
 3:
        /* Disable access to user memory */
-       csrc sstatus, t6
+       csrc CSR_SSTATUS, t6
        li a0, 0
        ret
 4: /* Edge case: unalignment */
@@ -72,7 +72,7 @@ ENTRY(__clear_user)
 
        /* Enable access to user memory */
        li t6, SR_SUM
-       csrs sstatus, t6
+       csrs CSR_SSTATUS, t6
 
        add a3, a0, a1
        addi t0, a0, SZREG-1
@@ -94,7 +94,7 @@ ENTRY(__clear_user)
 
 3:
        /* Disable access to user memory */
-       csrc sstatus, t6
+       csrc CSR_SSTATUS, t6
        li a0, 0
        ret
 4: /* Edge case: unalignment */
@@ -114,11 +114,11 @@ ENDPROC(__clear_user)
        /* Fixup code for __copy_user(10) and __clear_user(11) */
 10:
        /* Disable access to user memory */
-       csrs sstatus, t6
+       csrs CSR_SSTATUS, t6
        mv a0, a2
        ret
 11:
-       csrs sstatus, t6
+       csrs CSR_SSTATUS, t6
        mv a0, a1
        ret
        .previous
index 74055e1..9d9a173 100644 (file)
@@ -13,4 +13,7 @@ obj-y += cacheflush.o
 obj-y += context.o
 obj-y += sifive_l2_cache.o
 
+ifeq ($(CONFIG_MMU),y)
+obj-$(CONFIG_SMP) += tlbflush.o
+endif
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
index 9ebcff8..3f15938 100644 (file)
@@ -47,7 +47,6 @@ void flush_icache_mm(struct mm_struct *mm, bool local)
        cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu));
        local |= cpumask_empty(&others);
        if (mm != current->active_mm || !local) {
-               cpumask_clear(&hmask);
                riscv_cpuid_to_hartid_mask(&others, &hmask);
                sbi_remote_fence_i(hmask.bits);
        } else {
index 89ceb3c..beeb5d7 100644 (file)
@@ -57,12 +57,7 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        cpumask_clear_cpu(cpu, mm_cpumask(prev));
        cpumask_set_cpu(cpu, mm_cpumask(next));
 
-       /*
-        * Use the old spbtr name instead of using the current satp
-        * name to support binutils 2.29 which doesn't know about the
-        * privileged ISA 1.10 yet.
-        */
-       csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE);
+       csr_write(CSR_SATP, virt_to_pfn(next->pgd) | SATP_MODE);
        local_flush_tlb_all();
 
        flush_icache_deferred(next);
index 42bf939..f0ba713 100644 (file)
@@ -435,13 +435,23 @@ static void __init setup_vm_final(void)
        clear_fixmap(FIX_PMD);
 
        /* Move to swapper page table */
-       csr_write(sptbr, PFN_DOWN(__pa(swapper_pg_dir)) | SATP_MODE);
+       csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | SATP_MODE);
        local_flush_tlb_all();
 }
 
 void __init paging_init(void)
 {
        setup_vm_final();
+       memblocks_present();
+       sparse_init();
        setup_zero_page();
        zone_sizes_init();
 }
+
+#ifdef CONFIG_SPARSEMEM
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
+                              struct vmem_altmap *altmap)
+{
+       return vmemmap_populate_basepages(start, end, node);
+}
+#endif
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
new file mode 100644 (file)
index 0000000..24cd33d
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <asm/sbi.h>
+
+void flush_tlb_all(void)
+{
+       sbi_remote_sfence_vma(NULL, 0, -1);
+}
+
+static void __sbi_tlb_flush_range(struct cpumask *cmask, unsigned long start,
+                                 unsigned long size)
+{
+       struct cpumask hmask;
+
+       riscv_cpuid_to_hartid_mask(cmask, &hmask);
+       sbi_remote_sfence_vma(hmask.bits, start, size);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       __sbi_tlb_flush_range(mm_cpumask(mm), 0, -1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), addr, PAGE_SIZE);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                    unsigned long end)
+{
+       __sbi_tlb_flush_range(mm_cpumask(vma->vm_mm), start, end - start);
+}
index b5fd6e8..d1ccc16 100644 (file)
@@ -1961,6 +1961,16 @@ int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
        case KVM_S390_MCHK:
                irq->u.mchk.mcic = s390int->parm64;
                break;
+       case KVM_S390_INT_PFAULT_INIT:
+               irq->u.ext.ext_params = s390int->parm;
+               irq->u.ext.ext_params2 = s390int->parm64;
+               break;
+       case KVM_S390_RESTART:
+       case KVM_S390_INT_CLOCK_COMP:
+       case KVM_S390_INT_CPU_TIMER:
+               break;
+       default:
+               return -EINVAL;
        }
        return 0;
 }
index f329dcb..39cff07 100644 (file)
@@ -1018,6 +1018,8 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
        /* mark all the pages in active slots as dirty */
        for (slotnr = 0; slotnr < slots->used_slots; slotnr++) {
                ms = slots->memslots + slotnr;
+               if (!ms->dirty_bitmap)
+                       return -EINVAL;
                /*
                 * The second half of the bitmap is only used on x86,
                 * and would be wasted otherwise, so we put it to good
@@ -4323,7 +4325,7 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp,
        }
        case KVM_S390_INTERRUPT: {
                struct kvm_s390_interrupt s390int;
-               struct kvm_s390_irq s390irq;
+               struct kvm_s390_irq s390irq = {};
 
                if (copy_from_user(&s390int, argp, sizeof(s390int)))
                        return -EFAULT;
index e636728..955eb35 100644 (file)
@@ -863,7 +863,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
                break;
        case BPF_ALU64 | BPF_NEG: /* dst = -dst */
                /* lcgr %dst,%dst */
-               EMIT4(0xb9130000, dst_reg, dst_reg);
+               EMIT4(0xb9030000, dst_reg, dst_reg);
                break;
        /*
         * BPF_FROM_BE/LE
@@ -1049,8 +1049,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
                /* llgf %w1,map.max_entries(%b2) */
                EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
                              offsetof(struct bpf_array, map.max_entries));
-               /* clgrj %b3,%w1,0xa,label0: if %b3 >= %w1 goto out */
-               EMIT6_PCREL_LABEL(0xec000000, 0x0065, BPF_REG_3,
+               /* clrj %b3,%w1,0xa,label0: if (u32)%b3 >= (u32)%w1 goto out */
+               EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3,
                                  REG_W1, 0, 0xa);
 
                /*
@@ -1076,8 +1076,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
                 *         goto out;
                 */
 
-               /* sllg %r1,%b3,3: %r1 = index * 8 */
-               EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, BPF_REG_3, REG_0, 3);
+               /* llgfr %r1,%b3: %r1 = (u32) index */
+               EMIT4(0xb9160000, REG_1, BPF_REG_3);
+               /* sllg %r1,%r1,3: %r1 *= 8 */
+               EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, REG_1, REG_0, 3);
                /* lg %r1,prog(%b2,%r1) */
                EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, BPF_REG_2,
                              REG_1, offsetof(struct bpf_array, ptrs));
index defebf1..8455437 100644 (file)
@@ -475,8 +475,6 @@ static void print_sh_insn(u32 memaddr, u16 insn)
                                printk("dbr");
                                break;
                        case FD_REG_N:
-                               if (0)
-                                       goto d_reg_n;
                        case F_REG_N:
                                printk("fr%d", rn);
                                break;
@@ -488,7 +486,7 @@ static void print_sh_insn(u32 memaddr, u16 insn)
                                        printk("xd%d", rn & ~1);
                                        break;
                                }
-                       d_reg_n:
+                               /* else, fall through */
                        case D_REG_N:
                                printk("dr%d", rn);
                                break;
@@ -497,6 +495,7 @@ static void print_sh_insn(u32 memaddr, u16 insn)
                                        printk("xd%d", rm & ~1);
                                        break;
                                }
+                               /* else, fall through */
                        case D_REG_M:
                                printk("dr%d", rm);
                                break;
index 3bd010b..f10d643 100644 (file)
@@ -157,6 +157,7 @@ int arch_bp_generic_fields(int sh_len, int sh_type,
        switch (sh_type) {
        case SH_BREAKPOINT_READ:
                *gen_type = HW_BREAKPOINT_R;
+               break;
        case SH_BREAKPOINT_WRITE:
                *gen_type = HW_BREAKPOINT_W;
                break;
index ccc8892..9f41a6f 100644 (file)
@@ -336,25 +336,28 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
 {
        long err;
 
+       if (!IS_ENABLED(CONFIG_SYSVIPC))
+               return -ENOSYS;
+
        /* No need for backward compatibility. We can start fresh... */
        if (call <= SEMTIMEDOP) {
                switch (call) {
                case SEMOP:
-                       err = sys_semtimedop(first, ptr,
-                                            (unsigned int)second, NULL);
+                       err = ksys_semtimedop(first, ptr,
+                                             (unsigned int)second, NULL);
                        goto out;
                case SEMTIMEDOP:
-                       err = sys_semtimedop(first, ptr, (unsigned int)second,
+                       err = ksys_semtimedop(first, ptr, (unsigned int)second,
                                (const struct __kernel_timespec __user *)
-                                            (unsigned long) fifth);
+                                             (unsigned long) fifth);
                        goto out;
                case SEMGET:
-                       err = sys_semget(first, (int)second, (int)third);
+                       err = ksys_semget(first, (int)second, (int)third);
                        goto out;
                case SEMCTL: {
-                       err = sys_semctl(first, second,
-                                        (int)third | IPC_64,
-                                        (unsigned long) ptr);
+                       err = ksys_old_semctl(first, second,
+                                             (int)third | IPC_64,
+                                             (unsigned long) ptr);
                        goto out;
                }
                default:
@@ -365,18 +368,18 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
        if (call <= MSGCTL) {
                switch (call) {
                case MSGSND:
-                       err = sys_msgsnd(first, ptr, (size_t)second,
+                       err = ksys_msgsnd(first, ptr, (size_t)second,
                                         (int)third);
                        goto out;
                case MSGRCV:
-                       err = sys_msgrcv(first, ptr, (size_t)second, fifth,
+                       err = ksys_msgrcv(first, ptr, (size_t)second, fifth,
                                         (int)third);
                        goto out;
                case MSGGET:
-                       err = sys_msgget((key_t)first, (int)second);
+                       err = ksys_msgget((key_t)first, (int)second);
                        goto out;
                case MSGCTL:
-                       err = sys_msgctl(first, (int)second | IPC_64, ptr);
+                       err = ksys_old_msgctl(first, (int)second | IPC_64, ptr);
                        goto out;
                default:
                        err = -ENOSYS;
@@ -396,13 +399,13 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                        goto out;
                }
                case SHMDT:
-                       err = sys_shmdt(ptr);
+                       err = ksys_shmdt(ptr);
                        goto out;
                case SHMGET:
-                       err = sys_shmget(first, (size_t)second, (int)third);
+                       err = ksys_shmget(first, (size_t)second, (int)third);
                        goto out;
                case SHMCTL:
-                       err = sys_shmctl(first, (int)second | IPC_64, ptr);
+                       err = ksys_old_shmctl(first, (int)second | IPC_64, ptr);
                        goto out;
                default:
                        err = -ENOSYS;
index 8574338..9991ec2 100644 (file)
@@ -34,10 +34,13 @@ static inline void time_travel_set_time(unsigned long long ns)
        time_travel_time = ns;
 }
 
-static inline void time_travel_set_timer(enum time_travel_timer_mode mode,
-                                        unsigned long long expiry)
+static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
 {
        time_travel_timer_mode = mode;
+}
+
+static inline void time_travel_set_timer_expiry(unsigned long long expiry)
+{
        time_travel_timer_expiry = expiry;
 }
 #else
@@ -50,8 +53,11 @@ static inline void time_travel_set_time(unsigned long long ns)
 {
 }
 
-static inline void time_travel_set_timer(enum time_travel_timer_mode mode,
-                                        unsigned long long expiry)
+static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
+{
+}
+
+static inline void time_travel_set_timer_expiry(unsigned long long expiry)
 {
 }
 
index 67c0d1a..6bede78 100644 (file)
@@ -213,7 +213,7 @@ static void time_travel_sleep(unsigned long long duration)
        if (time_travel_timer_mode != TT_TMR_DISABLED ||
            time_travel_timer_expiry < next) {
                if (time_travel_timer_mode == TT_TMR_ONESHOT)
-                       time_travel_set_timer(TT_TMR_DISABLED, 0);
+                       time_travel_set_timer_mode(TT_TMR_DISABLED);
                /*
                 * time_travel_time will be adjusted in the timer
                 * IRQ handler so it works even when the signal
index 6a051b0..2347572 100644 (file)
@@ -50,7 +50,7 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
 static int itimer_shutdown(struct clock_event_device *evt)
 {
        if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_DISABLED, 0);
+               time_travel_set_timer_mode(TT_TMR_DISABLED);
 
        if (time_travel_mode != TT_MODE_INFCPU)
                os_timer_disable();
@@ -62,9 +62,10 @@ static int itimer_set_periodic(struct clock_event_device *evt)
 {
        unsigned long long interval = NSEC_PER_SEC / HZ;
 
-       if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_PERIODIC,
-                                     time_travel_time + interval);
+       if (time_travel_mode != TT_MODE_OFF) {
+               time_travel_set_timer_mode(TT_TMR_PERIODIC);
+               time_travel_set_timer_expiry(time_travel_time + interval);
+       }
 
        if (time_travel_mode != TT_MODE_INFCPU)
                os_timer_set_interval(interval);
@@ -77,9 +78,10 @@ static int itimer_next_event(unsigned long delta,
 {
        delta += 1;
 
-       if (time_travel_mode != TT_MODE_OFF)
-               time_travel_set_timer(TT_TMR_ONESHOT,
-                                     time_travel_time + delta);
+       if (time_travel_mode != TT_MODE_OFF) {
+               time_travel_set_timer_mode(TT_TMR_ONESHOT);
+               time_travel_set_timer_expiry(time_travel_time + delta);
+       }
 
        if (time_travel_mode != TT_MODE_INFCPU)
                return os_timer_one_shot(delta);
index d112982..c014ae3 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/kallsyms.h>
 #include <linux/proc_fs.h>
 #include <linux/syscore_ops.h>
-#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 
index 56e748a..94df086 100644 (file)
@@ -38,6 +38,7 @@ REALMODE_CFLAGS       := $(M16_CFLAGS) -g -Os -DDISABLE_BRANCH_PROFILING \
 
 REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -ffreestanding)
 REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -fno-stack-protector)
+REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), -Wno-address-of-packed-member)
 REALMODE_CFLAGS += $(call __cc-option, $(CC), $(REALMODE_CFLAGS), $(cc_stack_align4))
 export REALMODE_CFLAGS
 
index 5f2d030..c886269 100644 (file)
@@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
 
        /* Find the first usable memory region under bios_start. */
        for (i = boot_params->e820_entries - 1; i >= 0; i--) {
+               unsigned long new = bios_start;
+
                entry = &boot_params->e820_table[i];
 
                /* Skip all entries above bios_start. */
@@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
 
                /* Adjust bios_start to the end of the entry if needed. */
                if (bios_start > entry->addr + entry->size)
-                       bios_start = entry->addr + entry->size;
+                       new = entry->addr + entry->size;
 
                /* Keep bios_start page-aligned. */
-               bios_start = round_down(bios_start, PAGE_SIZE);
+               new = round_down(new, PAGE_SIZE);
 
                /* Skip the entry if it's too small. */
-               if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
+               if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
                        continue;
 
+               /* Protect against underflow. */
+               if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
+                       break;
+
+               bios_start = new;
                break;
        }
 
index 62f317c..5b35b7e 100644 (file)
@@ -661,10 +661,17 @@ fail:
 
        throttle = perf_event_overflow(event, &data, &regs);
 out:
-       if (throttle)
+       if (throttle) {
                perf_ibs_stop(event, 0);
-       else
-               perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+       } else {
+               period >>= 4;
+
+               if ((ibs_caps & IBS_CAPS_RDWROPCNT) &&
+                   (*config & IBS_OP_CNT_CTL))
+                       period |= *config & IBS_OP_CUR_CNT_RAND;
+
+               perf_ibs_enable_event(perf_ibs, hwc, period);
+       }
 
        perf_event_update_userpage(event);
 
index 81b005e..325959d 100644 (file)
@@ -1236,7 +1236,7 @@ void x86_pmu_enable_event(struct perf_event *event)
  * Add a single event to the PMU.
  *
  * The event is added to the group of enabled events
- * but only if it can be scehduled with existing events.
+ * but only if it can be scheduled with existing events.
  */
 static int x86_pmu_add(struct perf_event *event, int flags)
 {
index 648260b..e4c2cb6 100644 (file)
@@ -3572,6 +3572,11 @@ static u64 bdw_limit_period(struct perf_event *event, u64 left)
        return left;
 }
 
+static u64 nhm_limit_period(struct perf_event *event, u64 left)
+{
+       return max(left, 32ULL);
+}
+
 PMU_FORMAT_ATTR(event, "config:0-7"    );
 PMU_FORMAT_ATTR(umask, "config:8-15"   );
 PMU_FORMAT_ATTR(edge,  "config:18"     );
@@ -4606,6 +4611,7 @@ __init int intel_pmu_init(void)
                x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints;
                x86_pmu.enable_all = intel_pmu_nhm_enable_all;
                x86_pmu.extra_regs = intel_nehalem_extra_regs;
+               x86_pmu.limit_period = nhm_limit_period;
 
                mem_attr = nhm_mem_events_attrs;
 
index e65d7fe..5208ba4 100644 (file)
@@ -37,12 +37,14 @@ static inline int fill_gva_list(u64 gva_list[], int offset,
                 * Lower 12 bits encode the number of additional
                 * pages to flush (in addition to the 'cur' page).
                 */
-               if (diff >= HV_TLB_FLUSH_UNIT)
+               if (diff >= HV_TLB_FLUSH_UNIT) {
                        gva_list[gva_n] |= ~PAGE_MASK;
-               else if (diff)
+                       cur += HV_TLB_FLUSH_UNIT;
+               }  else if (diff) {
                        gva_list[gva_n] |= (diff - 1) >> PAGE_SHIFT;
+                       cur = end;
+               }
 
-               cur += HV_TLB_FLUSH_UNIT;
                gva_n++;
 
        } while (cur < end);
index 101eb94..981fe92 100644 (file)
  * Note: efi_info is commonly left uninitialized, but that field has a
  * private magic, so it is better to leave it unchanged.
  */
+
+#define sizeof_mbr(type, member) ({ sizeof(((type *)0)->member); })
+
+#define BOOT_PARAM_PRESERVE(struct_member)                             \
+       {                                                               \
+               .start = offsetof(struct boot_params, struct_member),   \
+               .len   = sizeof_mbr(struct boot_params, struct_member), \
+       }
+
+struct boot_params_to_save {
+       unsigned int start;
+       unsigned int len;
+};
+
 static void sanitize_boot_params(struct boot_params *boot_params)
 {
        /* 
@@ -35,21 +49,41 @@ static void sanitize_boot_params(struct boot_params *boot_params)
         * problems again.
         */
        if (boot_params->sentinel) {
-               /* fields in boot_params are left uninitialized, clear them */
-               boot_params->acpi_rsdp_addr = 0;
-               memset(&boot_params->ext_ramdisk_image, 0,
-                      (char *)&boot_params->efi_info -
-                       (char *)&boot_params->ext_ramdisk_image);
-               memset(&boot_params->kbd_status, 0,
-                      (char *)&boot_params->hdr -
-                      (char *)&boot_params->kbd_status);
-               memset(&boot_params->_pad7[0], 0,
-                      (char *)&boot_params->edd_mbr_sig_buffer[0] -
-                       (char *)&boot_params->_pad7[0]);
-               memset(&boot_params->_pad8[0], 0,
-                      (char *)&boot_params->eddbuf[0] -
-                       (char *)&boot_params->_pad8[0]);
-               memset(&boot_params->_pad9[0], 0, sizeof(boot_params->_pad9));
+               static struct boot_params scratch;
+               char *bp_base = (char *)boot_params;
+               char *save_base = (char *)&scratch;
+               int i;
+
+               const struct boot_params_to_save to_save[] = {
+                       BOOT_PARAM_PRESERVE(screen_info),
+                       BOOT_PARAM_PRESERVE(apm_bios_info),
+                       BOOT_PARAM_PRESERVE(tboot_addr),
+                       BOOT_PARAM_PRESERVE(ist_info),
+                       BOOT_PARAM_PRESERVE(hd0_info),
+                       BOOT_PARAM_PRESERVE(hd1_info),
+                       BOOT_PARAM_PRESERVE(sys_desc_table),
+                       BOOT_PARAM_PRESERVE(olpc_ofw_header),
+                       BOOT_PARAM_PRESERVE(efi_info),
+                       BOOT_PARAM_PRESERVE(alt_mem_k),
+                       BOOT_PARAM_PRESERVE(scratch),
+                       BOOT_PARAM_PRESERVE(e820_entries),
+                       BOOT_PARAM_PRESERVE(eddbuf_entries),
+                       BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
+                       BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
+                       BOOT_PARAM_PRESERVE(secure_boot),
+                       BOOT_PARAM_PRESERVE(hdr),
+                       BOOT_PARAM_PRESERVE(e820_table),
+                       BOOT_PARAM_PRESERVE(eddbuf),
+               };
+
+               memset(&scratch, 0, sizeof(scratch));
+
+               for (i = 0; i < ARRAY_SIZE(to_save); i++) {
+                       memcpy(save_base + to_save[i].start,
+                              bp_base + to_save[i].start, to_save[i].len);
+               }
+
+               memcpy(boot_params, save_base, sizeof(*boot_params));
        }
 }
 
diff --git a/arch/x86/include/asm/error-injection.h b/arch/x86/include/asm/error-injection.h
deleted file mode 100644 (file)
index 47b7a12..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_ERROR_INJECTION_H
-#define _ASM_ERROR_INJECTION_H
-
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm-generic/error-injection.h>
-
-asmlinkage void just_return_func(void);
-void override_function_with_return(struct pt_regs *regs);
-
-#endif /* _ASM_ERROR_INJECTION_H */
index 287f1f7..c38a666 100644 (file)
@@ -16,7 +16,6 @@
 #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
 
 #ifndef __ASSEMBLY__
-extern void mcount(void);
 extern atomic_t modifying_ftrace_code;
 extern void __fentry__(void);
 
index 0278aa6..fe7c205 100644 (file)
  * While adding a new CPUID for a new microarchitecture, add a new
  * group to keep logically sorted out in chronological order. Within
  * that group keep the CPUID for the variants sorted by model number.
+ *
+ * The defined symbol names have the following form:
+ *     INTEL_FAM6{OPTFAMILY}_{MICROARCH}{OPTDIFF}
+ * where:
+ * OPTFAMILY   Describes the family of CPUs that this belongs to. Default
+ *             is assumed to be "_CORE" (and should be omitted). Other values
+ *             currently in use are _ATOM and _XEON_PHI
+ * MICROARCH   Is the code name for the micro-architecture for this core.
+ *             N.B. Not the platform name.
+ * OPTDIFF     If needed, a short string to differentiate by market segment.
+ *             Exact strings here will vary over time. _DESKTOP, _MOBILE, and
+ *             _X (short for Xeon server) should be used when they are
+ *             appropriate.
+ *
+ * The #define line may optionally include a comment including platform names.
  */
 
 #define INTEL_FAM6_CORE_YONAH          0x0E
index baedab8..b91623d 100644 (file)
@@ -4,7 +4,6 @@
 
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
-extern int iommu_pass_through;
 
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
index 74e88e5..bdc16b0 100644 (file)
@@ -335,6 +335,7 @@ struct kvm_mmu_page {
        int root_count;          /* Currently serving as active root */
        unsigned int unsync_children;
        struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */
+       unsigned long mmu_valid_gen;
        DECLARE_BITMAP(unsync_child_bitmap, 512);
 
 #ifdef CONFIG_X86_32
@@ -856,6 +857,7 @@ struct kvm_arch {
        unsigned long n_requested_mmu_pages;
        unsigned long n_max_mmu_pages;
        unsigned int indirect_shadow_pages;
+       unsigned long mmu_valid_gen;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
        /*
         * Hash table of struct kvm_mmu_page.
index 6b4fc27..271d837 100644 (file)
 #define MSR_AMD64_PATCH_LEVEL          0x0000008b
 #define MSR_AMD64_TSC_RATIO            0xc0000104
 #define MSR_AMD64_NB_CFG               0xc001001f
+#define MSR_AMD64_CPUID_FN_1           0xc0011004
 #define MSR_AMD64_PATCH_LOADER         0xc0010020
 #define MSR_AMD64_OSVW_ID_LENGTH       0xc0010140
 #define MSR_AMD64_OSVW_STATUS          0xc0010141
index 109f974..80bc209 100644 (file)
        "       lfence;\n"                                      \
        "       jmp    902b;\n"                                 \
        "       .align 16\n"                                    \
-       "903:   addl   $4, %%esp;\n"                            \
+       "903:   lea    4(%%esp), %%esp;\n"                      \
        "       pushl  %[thunk_target];\n"                      \
        "       ret;\n"                                         \
        "       .align 16\n"                                    \
index 1392d5e..ee26e92 100644 (file)
@@ -252,16 +252,20 @@ struct pebs_lbr {
 #define IBSCTL_LVT_OFFSET_VALID                (1ULL<<8)
 #define IBSCTL_LVT_OFFSET_MASK         0x0F
 
-/* ibs fetch bits/masks */
+/* IBS fetch bits/masks */
 #define IBS_FETCH_RAND_EN      (1ULL<<57)
 #define IBS_FETCH_VAL          (1ULL<<49)
 #define IBS_FETCH_ENABLE       (1ULL<<48)
 #define IBS_FETCH_CNT          0xFFFF0000ULL
 #define IBS_FETCH_MAX_CNT      0x0000FFFFULL
 
-/* ibs op bits/masks */
-/* lower 4 bits of the current count are ignored: */
-#define IBS_OP_CUR_CNT         (0xFFFF0ULL<<32)
+/*
+ * IBS op bits/masks
+ * The lower 7 bits of the current count are random bits
+ * preloaded by hardware and ignored in software
+ */
+#define IBS_OP_CUR_CNT         (0xFFF80ULL<<32)
+#define IBS_OP_CUR_CNT_RAND    (0x0007FULL<<32)
 #define IBS_OP_CNT_CTL         (1ULL<<19)
 #define IBS_OP_VAL             (1ULL<<18)
 #define IBS_OP_ENABLE          (1ULL<<17)
index 9c44353..35c225e 100644 (file)
@@ -444,8 +444,10 @@ __pu_label:                                                        \
 ({                                                                     \
        int __gu_err;                                                   \
        __inttype(*(ptr)) __gu_val;                                     \
+       __typeof__(ptr) __gu_ptr = (ptr);                               \
+       __typeof__(size) __gu_size = (size);                            \
        __uaccess_begin_nospec();                                       \
-       __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);    \
+       __get_user_size(__gu_val, __gu_ptr, __gu_size, __gu_err, -EFAULT);      \
        __uaccess_end();                                                \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
        __builtin_expect(__gu_err, 0);                                  \
index d63e63b..251c795 100644 (file)
@@ -21,6 +21,7 @@
 #define PCI_DEVICE_ID_AMD_17H_DF_F4    0x1464
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
 
 /* Protect the PCI config register pairs used for SMN and DF indirect access. */
 static DEFINE_MUTEX(smn_mutex);
@@ -50,6 +51,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
        {}
 };
 EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
@@ -63,6 +65,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
        {}
 };
index f529136..08fb79f 100644 (file)
@@ -722,7 +722,7 @@ static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
 static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
 
 /*
- * Temporary interrupt handler.
+ * Temporary interrupt handler and polled calibration function.
  */
 static void __init lapic_cal_handler(struct clock_event_device *dev)
 {
@@ -834,6 +834,10 @@ bool __init apic_needs_pit(void)
        if (!boot_cpu_has(X86_FEATURE_APIC))
                return true;
 
+       /* Virt guests may lack ARAT, but still have DEADLINE */
+       if (!boot_cpu_has(X86_FEATURE_ARAT))
+               return true;
+
        /* Deadline timer is based on TSC so no further PIT action required */
        if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
                return false;
@@ -851,7 +855,8 @@ bool __init apic_needs_pit(void)
 static int __init calibrate_APIC_clock(void)
 {
        struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
-       void (*real_handler)(struct clock_event_device *dev);
+       u64 tsc_perj = 0, tsc_start = 0;
+       unsigned long jif_start;
        unsigned long deltaj;
        long delta, deltatsc;
        int pm_referenced = 0;
@@ -878,28 +883,64 @@ static int __init calibrate_APIC_clock(void)
        apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
                    "calibrating APIC timer ...\n");
 
+       /*
+        * There are platforms w/o global clockevent devices. Instead of
+        * making the calibration conditional on that, use a polling based
+        * approach everywhere.
+        */
        local_irq_disable();
 
-       /* Replace the global interrupt handler */
-       real_handler = global_clock_event->event_handler;
-       global_clock_event->event_handler = lapic_cal_handler;
-
        /*
         * Setup the APIC counter to maximum. There is no way the lapic
         * can underflow in the 100ms detection time frame
         */
        __setup_APIC_LVTT(0xffffffff, 0, 0);
 
-       /* Let the interrupts run */
+       /*
+        * Methods to terminate the calibration loop:
+        *  1) Global clockevent if available (jiffies)
+        *  2) TSC if available and frequency is known
+        */
+       jif_start = READ_ONCE(jiffies);
+
+       if (tsc_khz) {
+               tsc_start = rdtsc();
+               tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
+       }
+
+       /*
+        * Enable interrupts so the tick can fire, if a global
+        * clockevent device is available
+        */
        local_irq_enable();
 
-       while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
-               cpu_relax();
+       while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
+               /* Wait for a tick to elapse */
+               while (1) {
+                       if (tsc_khz) {
+                               u64 tsc_now = rdtsc();
+                               if ((tsc_now - tsc_start) >= tsc_perj) {
+                                       tsc_start += tsc_perj;
+                                       break;
+                               }
+                       } else {
+                               unsigned long jif_now = READ_ONCE(jiffies);
 
-       local_irq_disable();
+                               if (time_after(jif_now, jif_start)) {
+                                       jif_start = jif_now;
+                                       break;
+                               }
+                       }
+                       cpu_relax();
+               }
 
-       /* Restore the real event handler */
-       global_clock_event->event_handler = real_handler;
+               /* Invoke the calibration routine */
+               local_irq_disable();
+               lapic_cal_handler(NULL);
+               local_irq_enable();
+       }
+
+       local_irq_disable();
 
        /* Build delta t1-t2 as apic timer counts down */
        delta = lapic_cal_t1 - lapic_cal_t2;
@@ -943,10 +984,11 @@ static int __init calibrate_APIC_clock(void)
        levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
        /*
-        * PM timer calibration failed or not turned on
-        * so lets try APIC timer based calibration
+        * PM timer calibration failed or not turned on so lets try APIC
+        * timer based calibration, if a global clockevent device is
+        * available.
         */
-       if (!pm_referenced) {
+       if (!pm_referenced && global_clock_event) {
                apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
                /*
index afee386..caedd8d 100644 (file)
@@ -38,32 +38,12 @@ static int bigsmp_early_logical_apicid(int cpu)
        return early_per_cpu(x86_cpu_to_apicid, cpu);
 }
 
-static inline unsigned long calculate_ldr(int cpu)
-{
-       unsigned long val, id;
-
-       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-       id = per_cpu(x86_bios_cpu_apicid, cpu);
-       val |= SET_APIC_LOGICAL_ID(id);
-
-       return val;
-}
-
 /*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
+ * bigsmp enables physical destination mode
+ * and doesn't use LDR and DFR
  */
 static void bigsmp_init_apic_ldr(void)
 {
-       unsigned long val;
-       int cpu = smp_processor_id();
-
-       apic_write(APIC_DFR, APIC_DFR_FLAT);
-       val = calculate_ldr(cpu);
-       apic_write(APIC_LDR, val);
 }
 
 static void bigsmp_setup_apic_routing(void)
index c7bb6c6..d6af97f 100644 (file)
@@ -2438,7 +2438,13 @@ unsigned int arch_dynirq_lower_bound(unsigned int from)
         * dmar_alloc_hwirq() may be called before setup_IO_APIC(), so use
         * gsi_top if ioapic_dynirq_base hasn't been initialized yet.
         */
-       return ioapic_initialized ? ioapic_dynirq_base : gsi_top;
+       if (!ioapic_initialized)
+               return gsi_top;
+       /*
+        * For DT enabled machines ioapic_dynirq_base is irrelevant and not
+        * updated. So simply return @from if ioapic_dynirq_base == 0.
+        */
+       return ioapic_dynirq_base ? : from;
 }
 
 #ifdef CONFIG_X86_32
index 1492799..ee2d91e 100644 (file)
@@ -184,7 +184,8 @@ void __init default_setup_apic_routing(void)
                                def_to_bigsmp = 0;
                                break;
                        }
-                       /* If P4 and above fall through */
+                       /* P4 and above */
+                       /* fall through */
                case X86_VENDOR_HYGON:
                case X86_VENDOR_AMD:
                        def_to_bigsmp = 1;
index 8d4e504..68c363c 100644 (file)
@@ -804,6 +804,64 @@ static void init_amd_ln(struct cpuinfo_x86 *c)
        msr_set_bit(MSR_AMD64_DE_CFG, 31);
 }
 
+static bool rdrand_force;
+
+static int __init rdrand_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "force"))
+               rdrand_force = true;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+early_param("rdrand", rdrand_cmdline);
+
+static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
+{
+       /*
+        * Saving of the MSR used to hide the RDRAND support during
+        * suspend/resume is done by arch/x86/power/cpu.c, which is
+        * dependent on CONFIG_PM_SLEEP.
+        */
+       if (!IS_ENABLED(CONFIG_PM_SLEEP))
+               return;
+
+       /*
+        * The nordrand option can clear X86_FEATURE_RDRAND, so check for
+        * RDRAND support using the CPUID function directly.
+        */
+       if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
+               return;
+
+       msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62);
+
+       /*
+        * Verify that the CPUID change has occurred in case the kernel is
+        * running virtualized and the hypervisor doesn't support the MSR.
+        */
+       if (cpuid_ecx(1) & BIT(30)) {
+               pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n");
+               return;
+       }
+
+       clear_cpu_cap(c, X86_FEATURE_RDRAND);
+       pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n");
+}
+
+static void init_amd_jg(struct cpuinfo_x86 *c)
+{
+       /*
+        * Some BIOS implementations do not restore proper RDRAND support
+        * across suspend and resume. Check on whether to hide the RDRAND
+        * instruction support via CPUID.
+        */
+       clear_rdrand_cpuid_bit(c);
+}
+
 static void init_amd_bd(struct cpuinfo_x86 *c)
 {
        u64 value;
@@ -818,6 +876,13 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
                        wrmsrl_safe(MSR_F15H_IC_CFG, value);
                }
        }
+
+       /*
+        * Some BIOS implementations do not restore proper RDRAND support
+        * across suspend and resume. Check on whether to hide the RDRAND
+        * instruction support via CPUID.
+        */
+       clear_rdrand_cpuid_bit(c);
 }
 
 static void init_amd_zn(struct cpuinfo_x86 *c)
@@ -860,6 +925,7 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x10: init_amd_gh(c); break;
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
+       case 0x16: init_amd_jg(c); break;
        case 0x17: init_amd_zn(c); break;
        }
 
index 210f1f5..87bcdc6 100644 (file)
@@ -107,11 +107,11 @@ static struct severity {
         */
        MCESEV(
                AO, "Action optional: memory scrubbing error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB)
+               SER, MASK(MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB)
                ),
        MCESEV(
                AO, "Action optional: last level cache writeback error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
+               SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
                ),
 
        /* ignore OVER for UCNA */
index 6a204e7..32b4dc9 100644 (file)
  */
 static u32 umwait_control_cached = UMWAIT_CTRL_VAL(100000, UMWAIT_C02_ENABLE);
 
+/*
+ * Cache the original IA32_UMWAIT_CONTROL MSR value which is configured by
+ * hardware or BIOS before kernel boot.
+ */
+static u32 orig_umwait_control_cached __ro_after_init;
+
 /*
  * Serialize access to umwait_control_cached and IA32_UMWAIT_CONTROL MSR in
  * the sysfs write functions.
@@ -52,6 +58,23 @@ static int umwait_cpu_online(unsigned int cpu)
        return 0;
 }
 
+/*
+ * The CPU hotplug callback sets the control MSR to the original control
+ * value.
+ */
+static int umwait_cpu_offline(unsigned int cpu)
+{
+       /*
+        * This code is protected by the CPU hotplug already and
+        * orig_umwait_control_cached is never changed after it caches
+        * the original control MSR value in umwait_init(). So there
+        * is no race condition here.
+        */
+       wrmsr(MSR_IA32_UMWAIT_CONTROL, orig_umwait_control_cached, 0);
+
+       return 0;
+}
+
 /*
  * On resume, restore IA32_UMWAIT_CONTROL MSR on the boot processor which
  * is the only active CPU at this time. The MSR is set up on the APs via the
@@ -185,8 +208,22 @@ static int __init umwait_init(void)
        if (!boot_cpu_has(X86_FEATURE_WAITPKG))
                return -ENODEV;
 
+       /*
+        * Cache the original control MSR value before the control MSR is
+        * changed. This is the only place where orig_umwait_control_cached
+        * is modified.
+        */
+       rdmsrl(MSR_IA32_UMWAIT_CONTROL, orig_umwait_control_cached);
+
        ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "umwait:online",
-                               umwait_cpu_online, NULL);
+                               umwait_cpu_online, umwait_cpu_offline);
+       if (ret < 0) {
+               /*
+                * On failure, the control MSR on all CPUs has the
+                * original control value.
+                */
+               return ret;
+       }
 
        register_syscore_ops(&umwait_syscore_ops);
 
index f62b498..fa4352d 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/dma-direct.h>
 #include <linux/dma-debug.h>
+#include <linux/iommu.h>
 #include <linux/dmar.h>
 #include <linux/export.h>
 #include <linux/memblock.h>
@@ -34,21 +35,6 @@ int no_iommu __read_mostly;
 /* Set this to 1 if there is a HW IOMMU in the system */
 int iommu_detected __read_mostly = 0;
 
-/*
- * This variable becomes 1 if iommu=pt is passed on the kernel command line.
- * If this variable is 1, IOMMU implementations do no DMA translation for
- * devices and allow every device to access to whole physical memory. This is
- * useful if a user wants to use an IOMMU only for KVM device assignment to
- * guests and not for driver dma translation.
- * It is also possible to disable by default in kernel config, and enable with
- * iommu=nopt at boot time.
- */
-#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH
-int iommu_pass_through __read_mostly = 1;
-#else
-int iommu_pass_through __read_mostly;
-#endif
-
 extern struct iommu_table_entry __iommu_table[], __iommu_table_end[];
 
 void __init pci_iommu_alloc(void)
@@ -120,9 +106,9 @@ static __init int iommu_setup(char *p)
                        swiotlb = 1;
 #endif
                if (!strncmp(p, "pt", 2))
-                       iommu_pass_through = 1;
+                       iommu_set_default_passthrough(true);
                if (!strncmp(p, "nopt", 4))
-                       iommu_pass_through = 0;
+                       iommu_set_default_translated(true);
 
                gart_parse_options(p);
 
index d8359eb..8cd745e 100644 (file)
@@ -508,9 +508,12 @@ struct uprobe_xol_ops {
        void    (*abort)(struct arch_uprobe *, struct pt_regs *);
 };
 
-static inline int sizeof_long(void)
+static inline int sizeof_long(struct pt_regs *regs)
 {
-       return in_ia32_syscall() ? 4 : 8;
+       /*
+        * Check registers for mode as in_xxx_syscall() does not apply here.
+        */
+       return user_64bit_mode(regs) ? 8 : 4;
 }
 
 static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
@@ -521,9 +524,9 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
 
 static int emulate_push_stack(struct pt_regs *regs, unsigned long val)
 {
-       unsigned long new_sp = regs->sp - sizeof_long();
+       unsigned long new_sp = regs->sp - sizeof_long(regs);
 
-       if (copy_to_user((void __user *)new_sp, &val, sizeof_long()))
+       if (copy_to_user((void __user *)new_sp, &val, sizeof_long(regs)))
                return -EFAULT;
 
        regs->sp = new_sp;
@@ -556,7 +559,7 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
                long correction = utask->vaddr - utask->xol_vaddr;
                regs->ip += correction;
        } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
-               regs->sp += sizeof_long(); /* Pop incorrect return address */
+               regs->sp += sizeof_long(regs); /* Pop incorrect return address */
                if (emulate_push_stack(regs, utask->vaddr + auprobe->defparam.ilen))
                        return -ERESTART;
        }
@@ -675,7 +678,7 @@ static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
         * "call" insn was executed out-of-line. Just restore ->sp and restart.
         * We could also restore ->ip and try to call branch_emulate_op() again.
         */
-       regs->sp += sizeof_long();
+       regs->sp += sizeof_long(regs);
        return -ERESTART;
 }
 
@@ -1056,7 +1059,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 unsigned long
 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
 {
-       int rasize = sizeof_long(), nleft;
+       int rasize = sizeof_long(regs), nleft;
        unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
 
        if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
index c10a8b1..fff790a 100644 (file)
@@ -1781,7 +1781,7 @@ int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args)
 int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
                                struct kvm_cpuid_entry2 __user *entries)
 {
-       uint16_t evmcs_ver = kvm_x86_ops->nested_get_evmcs_version(vcpu);
+       uint16_t evmcs_ver = 0;
        struct kvm_cpuid_entry2 cpuid_entries[] = {
                { .function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS },
                { .function = HYPERV_CPUID_INTERFACE },
@@ -1793,6 +1793,9 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
        };
        int i, nent = ARRAY_SIZE(cpuid_entries);
 
+       if (kvm_x86_ops->nested_get_evmcs_version)
+               evmcs_ver = kvm_x86_ops->nested_get_evmcs_version(vcpu);
+
        /* Skip NESTED_FEATURES if eVMCS is not supported */
        if (!evmcs_ver)
                --nent;
index 685d17c..e904ff0 100644 (file)
@@ -216,6 +216,9 @@ static void recalculate_apic_map(struct kvm *kvm)
                if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])
                        new->phys_map[xapic_id] = apic;
 
+               if (!kvm_apic_sw_enabled(apic))
+                       continue;
+
                ldr = kvm_lapic_get_reg(apic, APIC_LDR);
 
                if (apic_x2apic_mode(apic)) {
@@ -258,6 +261,8 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
                        static_key_slow_dec_deferred(&apic_sw_disabled);
                else
                        static_key_slow_inc(&apic_sw_disabled.key);
+
+               recalculate_apic_map(apic->vcpu->kvm);
        }
 }
 
index 24843cf..a63964e 100644 (file)
@@ -2095,6 +2095,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct
        if (!direct)
                sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
        set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
+
+       /*
+        * active_mmu_pages must be a FIFO list, as kvm_zap_obsolete_pages()
+        * depends on valid pages being added to the head of the list.  See
+        * comments in kvm_zap_obsolete_pages().
+        */
        list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
        kvm_mod_used_mmu_pages(vcpu->kvm, +1);
        return sp;
@@ -2244,7 +2250,7 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
 #define for_each_valid_sp(_kvm, _sp, _gfn)                             \
        hlist_for_each_entry(_sp,                                       \
          &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \
-               if ((_sp)->role.invalid) {    \
+               if (is_obsolete_sp((_kvm), (_sp)) || (_sp)->role.invalid) {    \
                } else
 
 #define for_each_gfn_indirect_valid_sp(_kvm, _sp, _gfn)                        \
@@ -2301,6 +2307,11 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) { }
 static void mmu_audit_disable(void) { }
 #endif
 
+static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+       return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen);
+}
+
 static bool kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
                         struct list_head *invalid_list)
 {
@@ -2525,6 +2536,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                if (level > PT_PAGE_TABLE_LEVEL && need_sync)
                        flush |= kvm_sync_pages(vcpu, gfn, &invalid_list);
        }
+       sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
        clear_page(sp->spt);
        trace_kvm_mmu_get_page(sp, true);
 
@@ -4233,6 +4245,13 @@ static bool fast_cr3_switch(struct kvm_vcpu *vcpu, gpa_t new_cr3,
                        return false;
 
                if (cached_root_available(vcpu, new_cr3, new_role)) {
+                       /*
+                        * It is possible that the cached previous root page is
+                        * obsolete because of a change in the MMU generation
+                        * number. However, changing the generation number is
+                        * accompanied by KVM_REQ_MMU_RELOAD, which will free
+                        * the root set here and allocate a new one.
+                        */
                        kvm_make_request(KVM_REQ_LOAD_CR3, vcpu);
                        if (!skip_tlb_flush) {
                                kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
@@ -5649,44 +5668,91 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
        return alloc_mmu_pages(vcpu);
 }
 
-static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm,
-                       struct kvm_memory_slot *slot,
-                       struct kvm_page_track_notifier_node *node)
+
+static void kvm_zap_obsolete_pages(struct kvm *kvm)
 {
-       struct kvm_mmu_page *sp;
+       struct kvm_mmu_page *sp, *node;
        LIST_HEAD(invalid_list);
-       unsigned long i;
-       bool flush;
-       gfn_t gfn;
-
-       spin_lock(&kvm->mmu_lock);
-
-       if (list_empty(&kvm->arch.active_mmu_pages))
-               goto out_unlock;
-
-       flush = slot_handle_all_level(kvm, slot, kvm_zap_rmapp, false);
+       int ign;
 
-       for (i = 0; i < slot->npages; i++) {
-               gfn = slot->base_gfn + i;
+restart:
+       list_for_each_entry_safe_reverse(sp, node,
+             &kvm->arch.active_mmu_pages, link) {
+               /*
+                * No obsolete valid page exists before a newly created page
+                * since active_mmu_pages is a FIFO list.
+                */
+               if (!is_obsolete_sp(kvm, sp))
+                       break;
 
-               for_each_valid_sp(kvm, sp, gfn) {
-                       if (sp->gfn != gfn)
-                               continue;
+               /*
+                * Do not repeatedly zap a root page to avoid unnecessary
+                * KVM_REQ_MMU_RELOAD, otherwise we may not be able to
+                * progress:
+                *    vcpu 0                        vcpu 1
+                *                         call vcpu_enter_guest():
+                *                            1): handle KVM_REQ_MMU_RELOAD
+                *                                and require mmu-lock to
+                *                                load mmu
+                * repeat:
+                *    1): zap root page and
+                *        send KVM_REQ_MMU_RELOAD
+                *
+                *    2): if (cond_resched_lock(mmu-lock))
+                *
+                *                            2): hold mmu-lock and load mmu
+                *
+                *                            3): see KVM_REQ_MMU_RELOAD bit
+                *                                on vcpu->requests is set
+                *                                then return 1 to call
+                *                                vcpu_enter_guest() again.
+                *            goto repeat;
+                *
+                * Since we are reversely walking the list and the invalid
+                * list will be moved to the head, skip the invalid page
+                * can help us to avoid the infinity list walking.
+                */
+               if (sp->role.invalid)
+                       continue;
 
-                       kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
-               }
                if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
-                       kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
-                       flush = false;
+                       kvm_mmu_commit_zap_page(kvm, &invalid_list);
                        cond_resched_lock(&kvm->mmu_lock);
+                       goto restart;
                }
+
+               if (__kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list, &ign))
+                       goto restart;
        }
-       kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
 
-out_unlock:
+       kvm_mmu_commit_zap_page(kvm, &invalid_list);
+}
+
+/*
+ * Fast invalidate all shadow pages and use lock-break technique
+ * to zap obsolete pages.
+ *
+ * It's required when memslot is being deleted or VM is being
+ * destroyed, in these cases, we should ensure that KVM MMU does
+ * not use any resource of the being-deleted slot or all slots
+ * after calling the function.
+ */
+static void kvm_mmu_zap_all_fast(struct kvm *kvm)
+{
+       spin_lock(&kvm->mmu_lock);
+       kvm->arch.mmu_valid_gen++;
+
+       kvm_zap_obsolete_pages(kvm);
        spin_unlock(&kvm->mmu_lock);
 }
 
+static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm,
+                       struct kvm_memory_slot *slot,
+                       struct kvm_page_track_notifier_node *node)
+{
+       kvm_mmu_zap_all_fast(kvm);
+}
+
 void kvm_mmu_init_vm(struct kvm *kvm)
 {
        struct kvm_page_track_notifier_node *node = &kvm->arch.mmu_sp_tracker;
index d685491..e036807 100644 (file)
@@ -1714,7 +1714,6 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
        if (!entry)
                return -EINVAL;
 
-       new_entry = READ_ONCE(*entry);
        new_entry = __sme_set((page_to_phys(svm->avic_backing_page) &
                              AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) |
                              AVIC_PHYSICAL_ID_ENTRY_VALID_MASK);
@@ -7129,12 +7128,6 @@ failed:
        return ret;
 }
 
-static uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
-{
-       /* Not supported */
-       return 0;
-}
-
 static int nested_enable_evmcs(struct kvm_vcpu *vcpu,
                                   uint16_t *vmcs_version)
 {
@@ -7333,7 +7326,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .mem_enc_unreg_region = svm_unregister_enc_region,
 
        .nested_enable_evmcs = nested_enable_evmcs,
-       .nested_get_evmcs_version = nested_get_evmcs_version,
+       .nested_get_evmcs_version = NULL,
 
        .need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
 };
index ced9fba..a3cba32 100644 (file)
@@ -4540,6 +4540,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        int len;
        gva_t gva = 0;
        struct vmcs12 *vmcs12;
+       struct x86_exception e;
        short offset;
 
        if (!nested_vmx_check_permission(vcpu))
@@ -4588,7 +4589,8 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
                                vmx_instruction_info, true, len, &gva))
                        return 1;
                /* _system ok, nested_vmx_check_permission has verified cpl=0 */
-               kvm_write_guest_virt_system(vcpu, gva, &field_value, len, NULL);
+               if (kvm_write_guest_virt_system(vcpu, gva, &field_value, len, &e))
+                       kvm_inject_page_fault(vcpu, &e);
        }
 
        return nested_vmx_succeed(vcpu);
index 42ed3fa..c030c96 100644 (file)
@@ -7797,6 +7797,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .set_nested_state = NULL,
        .get_vmcs12_pages = NULL,
        .nested_enable_evmcs = NULL,
+       .nested_get_evmcs_version = NULL,
        .need_emulation_on_page_fault = vmx_need_emulation_on_page_fault,
 };
 
index 93b0bd4..91602d3 100644 (file)
@@ -5312,6 +5312,13 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
        /* kvm_write_guest_virt_system can pull in tons of pages. */
        vcpu->arch.l1tf_flush_l1d = true;
 
+       /*
+        * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED
+        * is returned, but our callers are not ready for that and they blindly
+        * call kvm_inject_page_fault.  Ensure that they at least do not leak
+        * uninitialized kernel stack memory into cr2 and error code.
+        */
+       memset(exception, 0, sizeof(*exception));
        return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
                                           PFERR_WRITE_MASK, exception);
 }
@@ -6594,12 +6601,13 @@ restart:
                unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
                toggle_interruptibility(vcpu, ctxt->interruptibility);
                vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
-               kvm_rip_write(vcpu, ctxt->eip);
-               if (r == EMULATE_DONE && ctxt->tf)
-                       kvm_vcpu_do_singlestep(vcpu, &r);
                if (!ctxt->have_exception ||
-                   exception_type(ctxt->exception.vector) == EXCPT_TRAP)
+                   exception_type(ctxt->exception.vector) == EXCPT_TRAP) {
+                       kvm_rip_write(vcpu, ctxt->eip);
+                       if (r == EMULATE_DONE && ctxt->tf)
+                               kvm_vcpu_do_singlestep(vcpu, &r);
                        __kvm_set_rflags(vcpu, ctxt->eflags);
+               }
 
                /*
                 * For STI, interrupts are shadowed; so KVM_REQ_EVENT will
index 6b46851..73dc66d 100644 (file)
@@ -178,13 +178,15 @@ void FPU_printall(void)
        for (i = 0; i < 8; i++) {
                FPU_REG *r = &st(i);
                u_char tagi = FPU_gettagi(i);
+
                switch (tagi) {
                case TAG_Empty:
                        continue;
-                       break;
                case TAG_Zero:
                case TAG_Special:
+                       /* Update tagi for the printk below */
                        tagi = FPU_Special(r);
+                       /* fall through */
                case TAG_Valid:
                        printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
                               getsign(r) ? '-' : '+',
@@ -198,7 +200,6 @@ void FPU_printall(void)
                        printk("Whoops! Error in errors.c: tag%d is %d ", i,
                               tagi);
                        continue;
-                       break;
                }
                printk("%s\n", tag_desc[(int)(unsigned)tagi]);
        }
index 783c509..127ea54 100644 (file)
@@ -1352,7 +1352,7 @@ static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
                case TW_Denormal:
                        if (denormal_operand() < 0)
                                return;
-
+                       /* fall through */
                case TAG_Zero:
                case TAG_Valid:
                        setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
index 6a9a77a..e14e95e 100644 (file)
@@ -516,7 +516,7 @@ static inline void check_conflict(int warnlvl, pgprot_t prot, pgprotval_t val,
  */
 static inline pgprot_t static_protections(pgprot_t prot, unsigned long start,
                                          unsigned long pfn, unsigned long npg,
-                                         int warnlvl)
+                                         unsigned long lpsize, int warnlvl)
 {
        pgprotval_t forbidden, res;
        unsigned long end;
@@ -535,9 +535,17 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long start,
        check_conflict(warnlvl, prot, res, start, end, pfn, "Text NX");
        forbidden = res;
 
-       res = protect_kernel_text_ro(start, end);
-       check_conflict(warnlvl, prot, res, start, end, pfn, "Text RO");
-       forbidden |= res;
+       /*
+        * Special case to preserve a large page. If the change spawns the
+        * full large page mapping then there is no point to split it
+        * up. Happens with ftrace and is going to be removed once ftrace
+        * switched to text_poke().
+        */
+       if (lpsize != (npg * PAGE_SIZE) || (start & (lpsize - 1))) {
+               res = protect_kernel_text_ro(start, end);
+               check_conflict(warnlvl, prot, res, start, end, pfn, "Text RO");
+               forbidden |= res;
+       }
 
        /* Check the PFN directly */
        res = protect_pci_bios(pfn, pfn + npg - 1);
@@ -819,7 +827,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
         * extra conditional required here.
         */
        chk_prot = static_protections(old_prot, lpaddr, old_pfn, numpages,
-                                     CPA_CONFLICT);
+                                     psize, CPA_CONFLICT);
 
        if (WARN_ON_ONCE(pgprot_val(chk_prot) != pgprot_val(old_prot))) {
                /*
@@ -855,7 +863,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
         * protection requirement in the large page.
         */
        new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages,
-                                     CPA_DETECT);
+                                     psize, CPA_DETECT);
 
        /*
         * If there is a conflict, split the large page.
@@ -906,7 +914,8 @@ static void split_set_pte(struct cpa_data *cpa, pte_t *pte, unsigned long pfn,
        if (!cpa->force_static_prot)
                goto set;
 
-       prot = static_protections(ref_prot, address, pfn, npg, CPA_PROTECT);
+       /* Hand in lpsize = 0 to enforce the protection mechanism */
+       prot = static_protections(ref_prot, address, pfn, npg, 0, CPA_PROTECT);
 
        if (pgprot_val(prot) == pgprot_val(ref_prot))
                goto set;
@@ -1503,7 +1512,8 @@ repeat:
                pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
 
                cpa_inc_4k_install();
-               new_prot = static_protections(new_prot, address, pfn, 1,
+               /* Hand in lpsize = 0 to enforce the protection mechanism */
+               new_prot = static_protections(new_prot, address, pfn, 1, 0,
                                              CPA_PROTECT);
 
                new_prot = pgprot_clear_protnone_bits(new_prot);
index eaaed5b..991549a 100644 (file)
@@ -390,8 +390,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
 
        emit_prologue(&prog, bpf_prog->aux->stack_depth,
                      bpf_prog_was_classic(bpf_prog));
+       addrs[0] = prog - temp;
 
-       for (i = 0; i < insn_cnt; i++, insn++) {
+       for (i = 1; i <= insn_cnt; i++, insn++) {
                const s32 imm32 = insn->imm;
                u32 dst_reg = insn->dst_reg;
                u32 src_reg = insn->src_reg;
@@ -1105,7 +1106,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
                extra_pass = true;
                goto skip_init_addrs;
        }
-       addrs = kmalloc_array(prog->len, sizeof(*addrs), GFP_KERNEL);
+       addrs = kmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL);
        if (!addrs) {
                prog = orig_prog;
                goto out_addrs;
@@ -1115,7 +1116,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
         * Before first pass, make a rough estimation of addrs[]
         * each BPF instruction is translated to less than 64 bytes
         */
-       for (proglen = 0, i = 0; i < prog->len; i++) {
+       for (proglen = 0, i = 0; i <= prog->len; i++) {
                proglen += 64;
                addrs[i] = proglen;
        }
@@ -1180,7 +1181,7 @@ out_image:
 
        if (!image || !prog->is_func || extra_pass) {
                if (image)
-                       bpf_prog_fill_jited_linfo(prog, addrs);
+                       bpf_prog_fill_jited_linfo(prog, addrs + 1);
 out_addrs:
                kfree(addrs);
                kfree(jit_data);
index 24b079e..c9ef6a7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 #include <linux/perf_event.h>
 #include <linux/tboot.h>
+#include <linux/dmi.h>
 
 #include <asm/pgtable.h>
 #include <asm/proto.h>
@@ -23,7 +24,7 @@
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
 #include <asm/mmu_context.h>
-#include <linux/dmi.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -397,15 +398,14 @@ static int __init bsp_pm_check_init(void)
 
 core_initcall(bsp_pm_check_init);
 
-static int msr_init_context(const u32 *msr_id, const int total_num)
+static int msr_build_context(const u32 *msr_id, const int num)
 {
-       int i = 0;
+       struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
        struct saved_msr *msr_array;
+       int total_num;
+       int i, j;
 
-       if (saved_context.saved_msrs.array || saved_context.saved_msrs.num > 0) {
-               pr_err("x86/pm: MSR quirk already applied, please check your DMI match table.\n");
-               return -EINVAL;
-       }
+       total_num = saved_msrs->num + num;
 
        msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
        if (!msr_array) {
@@ -413,19 +413,30 @@ static int msr_init_context(const u32 *msr_id, const int total_num)
                return -ENOMEM;
        }
 
-       for (i = 0; i < total_num; i++) {
-               msr_array[i].info.msr_no        = msr_id[i];
+       if (saved_msrs->array) {
+               /*
+                * Multiple callbacks can invoke this function, so copy any
+                * MSR save requests from previous invocations.
+                */
+               memcpy(msr_array, saved_msrs->array,
+                      sizeof(struct saved_msr) * saved_msrs->num);
+
+               kfree(saved_msrs->array);
+       }
+
+       for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
+               msr_array[i].info.msr_no        = msr_id[j];
                msr_array[i].valid              = false;
                msr_array[i].info.reg.q         = 0;
        }
-       saved_context.saved_msrs.num    = total_num;
-       saved_context.saved_msrs.array  = msr_array;
+       saved_msrs->num   = total_num;
+       saved_msrs->array = msr_array;
 
        return 0;
 }
 
 /*
- * The following section is a quirk framework for problematic BIOSen:
+ * The following sections are a quirk framework for problematic BIOSen:
  * Sometimes MSRs are modified by the BIOSen after suspended to
  * RAM, this might cause unexpected behavior after wakeup.
  * Thus we save/restore these specified MSRs across suspend/resume
@@ -440,7 +451,7 @@ static int msr_initialize_bdw(const struct dmi_system_id *d)
        u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
 
        pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
-       return msr_init_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
+       return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
 }
 
 static const struct dmi_system_id msr_save_dmi_table[] = {
@@ -455,9 +466,58 @@ static const struct dmi_system_id msr_save_dmi_table[] = {
        {}
 };
 
+static int msr_save_cpuid_features(const struct x86_cpu_id *c)
+{
+       u32 cpuid_msr_id[] = {
+               MSR_AMD64_CPUID_FN_1,
+       };
+
+       pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
+               c->family);
+
+       return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
+}
+
+static const struct x86_cpu_id msr_save_cpu_table[] = {
+       {
+               .vendor = X86_VENDOR_AMD,
+               .family = 0x15,
+               .model = X86_MODEL_ANY,
+               .feature = X86_FEATURE_ANY,
+               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+       },
+       {
+               .vendor = X86_VENDOR_AMD,
+               .family = 0x16,
+               .model = X86_MODEL_ANY,
+               .feature = X86_FEATURE_ANY,
+               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
+       },
+       {}
+};
+
+typedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);
+static int pm_cpu_check(const struct x86_cpu_id *c)
+{
+       const struct x86_cpu_id *m;
+       int ret = 0;
+
+       m = x86_match_cpu(msr_save_cpu_table);
+       if (m) {
+               pm_cpu_match_t fn;
+
+               fn = (pm_cpu_match_t)m->driver_data;
+               ret = fn(m);
+       }
+
+       return ret;
+}
+
 static int pm_check_save_msr(void)
 {
        dmi_check_system(msr_save_dmi_table);
+       pm_cpu_check(msr_save_cpu_table);
+
        return 0;
 }
 
index 8901a1f..10fb42d 100644 (file)
@@ -18,37 +18,40 @@ targets += purgatory.ro
 KASAN_SANITIZE := n
 KCOV_INSTRUMENT := n
 
+# These are adjustments to the compiler flags used for objects that
+# make up the standalone purgatory.ro
+
+PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
+PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss
+
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
 # sure how to relocate those.
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_sha256.o         += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_purgatory.o      += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_string.o         += $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_kexec-purgatory.o        += $(CC_FLAGS_FTRACE)
+PURGATORY_CFLAGS_REMOVE                += $(CC_FLAGS_FTRACE)
 endif
 
 ifdef CONFIG_STACKPROTECTOR
-CFLAGS_REMOVE_sha256.o         += -fstack-protector
-CFLAGS_REMOVE_purgatory.o      += -fstack-protector
-CFLAGS_REMOVE_string.o         += -fstack-protector
-CFLAGS_REMOVE_kexec-purgatory.o        += -fstack-protector
+PURGATORY_CFLAGS_REMOVE                += -fstack-protector
 endif
 
 ifdef CONFIG_STACKPROTECTOR_STRONG
-CFLAGS_REMOVE_sha256.o         += -fstack-protector-strong
-CFLAGS_REMOVE_purgatory.o      += -fstack-protector-strong
-CFLAGS_REMOVE_string.o         += -fstack-protector-strong
-CFLAGS_REMOVE_kexec-purgatory.o        += -fstack-protector-strong
+PURGATORY_CFLAGS_REMOVE                += -fstack-protector-strong
 endif
 
 ifdef CONFIG_RETPOLINE
-CFLAGS_REMOVE_sha256.o         += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_purgatory.o      += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_string.o         += $(RETPOLINE_CFLAGS)
-CFLAGS_REMOVE_kexec-purgatory.o        += $(RETPOLINE_CFLAGS)
+PURGATORY_CFLAGS_REMOVE                += $(RETPOLINE_CFLAGS)
 endif
 
+CFLAGS_REMOVE_purgatory.o      += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_purgatory.o             += $(PURGATORY_CFLAGS)
+
+CFLAGS_REMOVE_sha256.o         += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_sha256.o                        += $(PURGATORY_CFLAGS)
+
+CFLAGS_REMOVE_string.o         += $(PURGATORY_CFLAGS_REMOVE)
+CFLAGS_string.o                        += $(PURGATORY_CFLAGS)
+
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
                $(call if_changed,ld)
 
index 5cb8a62..7c31060 100644 (file)
@@ -511,6 +511,7 @@ void cpu_reset(void)
                                      "add      %2, %2, %7\n\t"
                                      "addi     %0, %0, -1\n\t"
                                      "bnez     %0, 1b\n\t"
+                                     "isync\n\t"
                                      /* Jump to identity mapping */
                                      "jx       %3\n"
                                      "2:\n\t"
index f78d328..0835f4d 100644 (file)
@@ -1958,13 +1958,9 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
        rq = blk_mq_get_request(q, bio, &data);
        if (unlikely(!rq)) {
                rq_qos_cleanup(q, bio);
-
-               cookie = BLK_QC_T_NONE;
-               if (bio->bi_opf & REQ_NOWAIT_INLINE)
-                       cookie = BLK_QC_T_EAGAIN;
-               else if (bio->bi_opf & REQ_NOWAIT)
+               if (bio->bi_opf & REQ_NOWAIT)
                        bio_wouldblock_error(bio);
-               return cookie;
+               return BLK_QC_T_NONE;
        }
 
        trace_block_getrq(q, bio, bio->bi_opf);
@@ -2666,8 +2662,6 @@ void blk_mq_release(struct request_queue *q)
        struct blk_mq_hw_ctx *hctx, *next;
        int i;
 
-       cancel_delayed_work_sync(&q->requeue_work);
-
        queue_for_each_hw_ctx(q, hctx, i)
                WARN_ON_ONCE(hctx && list_empty(&hctx->hctx_list));
 
index 977c659..9bfa3ea 100644 (file)
@@ -892,6 +892,9 @@ static void __blk_release_queue(struct work_struct *work)
 
        blk_free_queue_stats(q->stats);
 
+       if (queue_is_mq(q))
+               cancel_delayed_work_sync(&q->requeue_work);
+
        blk_exit_queue(q);
 
        blk_queue_free_zone_bitmaps(q);
index 61cf4ea..477d63d 100644 (file)
@@ -30,8 +30,6 @@ source "drivers/block/Kconfig"
 
 source "drivers/nvme/Kconfig"
 
-# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
-
 source "drivers/misc/Kconfig"
 
 source "drivers/ide/Kconfig"
index 6d37564..05be8c7 100644 (file)
@@ -132,7 +132,6 @@ obj-y                               += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-$(CONFIG_NEW_LEDS)         += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
-obj-$(CONFIG_SGI_SN)           += sn/
 obj-y                          += firmware/
 obj-$(CONFIG_CRYPTO)           += crypto/
 obj-$(CONFIG_SUPERH)           += sh/
index 5f61589..ebe1e9e 100644 (file)
@@ -323,7 +323,7 @@ config ACPI_NUMA
        bool "NUMA support"
        depends on NUMA
        depends on (X86 || IA64 || ARM64)
-       default y if IA64_GENERIC || IA64_SGI_SN2 || ARM64
+       default y if IA64 || ARM64
 
 config ACPI_CUSTOM_DSDT_FILE
        string "Custom DSDT Table file to include"
index 8569b79..5a7551d 100644 (file)
@@ -1256,12 +1256,12 @@ static int  __init arm_smmu_v3_set_proximity(struct device *dev,
 
        smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
        if (smmu->flags & ACPI_IORT_SMMU_V3_PXM_VALID) {
-               int node = acpi_map_pxm_to_node(smmu->pxm);
+               int dev_node = acpi_map_pxm_to_node(smmu->pxm);
 
-               if (node != NUMA_NO_NODE && !node_online(node))
+               if (dev_node != NUMA_NO_NODE && !node_online(dev_node))
                        return -EINVAL;
 
-               set_dev_node(dev, node);
+               set_dev_node(dev, dev_node);
                pr_info("SMMU-v3[%llx] Mapped to Proximity domain %d\n",
                        smmu->base_address,
                        smmu->pxm);
index 1e7ac0b..f31544d 100644 (file)
@@ -540,6 +540,44 @@ static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag)
        return retval;
 }
 
+/**
+ * check_acpi_cpu_flag() - Determine if CPU node has a flag set
+ * @cpu: Kernel logical CPU number
+ * @rev: The minimum PPTT revision defining the flag
+ * @flag: The flag itself
+ *
+ * Check the node representing a CPU for a given flag.
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, the CPU cannot be found or
+ *        the table revision isn't new enough.
+ *        1, any passed flag set
+ *        0, flag unset
+ */
+static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag)
+{
+       struct acpi_table_header *table;
+       acpi_status status;
+       u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+       struct acpi_pptt_processor *cpu_node = NULL;
+       int ret = -ENOENT;
+
+       status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+       if (ACPI_FAILURE(status)) {
+               acpi_pptt_warn_missing();
+               return ret;
+       }
+
+       if (table->revision >= rev)
+               cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+
+       if (cpu_node)
+               ret = (cpu_node->flags & flag) != 0;
+
+       acpi_put_table(table);
+
+       return ret;
+}
+
 /**
  * acpi_find_last_cache_level() - Determines the number of cache levels for a PE
  * @cpu: Kernel logical CPU number
@@ -604,6 +642,20 @@ int cache_setup_acpi(unsigned int cpu)
        return status;
 }
 
+/**
+ * acpi_pptt_cpu_is_thread() - Determine if CPU is a thread
+ * @cpu: Kernel logical CPU number
+ *
+ * Return: 1, a thread
+ *         0, not a thread
+ *         -ENOENT ,if the PPTT doesn't exist, the CPU cannot be found or
+ *         the table revision isn't new enough.
+ */
+int acpi_pptt_cpu_is_thread(unsigned int cpu)
+{
+       return check_acpi_cpu_flag(cpu, 2, ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD);
+}
+
 /**
  * find_acpi_cpu_topology() - Determine a unique topology value for a given CPU
  * @cpu: Kernel logical CPU number
@@ -664,7 +716,6 @@ int find_acpi_cpu_cache_topology(unsigned int cpu, int level)
        return ret;
 }
 
-
 /**
  * find_acpi_cpu_topology_package() - Determine a unique CPU package value
  * @cpu: Kernel logical CPU number
index 2e2efa5..8c37294 100644 (file)
@@ -200,7 +200,7 @@ config ATM_NICSTAR_USE_SUNI
          make the card work).
 
 config ATM_NICSTAR_USE_IDT77105
-       bool "Use IDT77015 PHY driver (25Mbps)"
+       bool "Use IDT77105 PHY driver (25Mbps)"
        depends on ATM_NICSTAR
        help
          Support for the PHYsical layer chip in ForeRunner LE25 cards. In
index dd61fdd..68489d1 100644 (file)
@@ -448,6 +448,11 @@ config PANEL_BOOT_MESSAGE
 choice
        prompt "Backlight initial state"
        default CHARLCD_BL_FLASH
+       ---help---
+         Select the initial backlight state on boot or module load.
+
+         Previously, there was no option for this: the backlight flashed
+         briefly on init. Now you can also turn it off/on.
 
        config CHARLCD_BL_OFF
                bool "Off"
index 92745ef..bef6b85 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <generated/utsrelease.h>
 
-#include <misc/charlcd.h>
+#include "charlcd.h"
 
 #define LCD_MINOR              156
 
diff --git a/drivers/auxdisplay/charlcd.h b/drivers/auxdisplay/charlcd.h
new file mode 100644 (file)
index 0000000..00911ad
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Character LCD driver for Linux
+ *
+ * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
+ * Copyright (C) 2016-2017 Glider bvba
+ */
+
+#ifndef _CHARLCD_H
+#define _CHARLCD_H
+
+struct charlcd {
+       const struct charlcd_ops *ops;
+       const unsigned char *char_conv; /* Optional */
+
+       int ifwidth;                    /* 4-bit or 8-bit (default) */
+       int height;
+       int width;
+       int bwidth;                     /* Default set by charlcd_alloc() */
+       int hwidth;                     /* Default set by charlcd_alloc() */
+
+       void *drvdata;                  /* Set by charlcd_alloc() */
+};
+
+struct charlcd_ops {
+       /* Required */
+       void (*write_cmd)(struct charlcd *lcd, int cmd);
+       void (*write_data)(struct charlcd *lcd, int data);
+
+       /* Optional */
+       void (*write_cmd_raw4)(struct charlcd *lcd, int cmd);   /* 4-bit only */
+       void (*clear_fast)(struct charlcd *lcd);
+       void (*backlight)(struct charlcd *lcd, int on);
+};
+
+struct charlcd *charlcd_alloc(unsigned int drvdata_size);
+void charlcd_free(struct charlcd *lcd);
+
+int charlcd_register(struct charlcd *lcd);
+int charlcd_unregister(struct charlcd *lcd);
+
+void charlcd_poke(struct charlcd *lcd);
+
+#endif /* CHARLCD_H */
index ab15b64..bcbe130 100644 (file)
@@ -14,8 +14,7 @@
 #include <linux/property.h>
 #include <linux/slab.h>
 
-#include <misc/charlcd.h>
-
+#include "charlcd.h"
 
 enum hd44780_pin {
        /* Order does matter due to writing to GPIO array subsets! */
index 9c0bb77..a2fcde5 100644 (file)
@@ -74,7 +74,7 @@ struct ht16k33_priv {
        struct ht16k33_fbdev fbdev;
 };
 
-static struct fb_fix_screeninfo ht16k33_fb_fix = {
+static const struct fb_fix_screeninfo ht16k33_fb_fix = {
        .id             = DRIVER_NAME,
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_MONO10,
@@ -85,7 +85,7 @@ static struct fb_fix_screeninfo ht16k33_fb_fix = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo ht16k33_fb_var = {
+static const struct fb_var_screeninfo ht16k33_fb_var = {
        .xres = HT16K33_MATRIX_LED_MAX_ROWS,
        .yres = HT16K33_MATRIX_LED_MAX_COLS,
        .xres_virtual = HT16K33_MATRIX_LED_MAX_ROWS,
index e06de63..8596595 100644 (file)
@@ -55,7 +55,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
-#include <misc/charlcd.h>
+#include "charlcd.h"
 
 #define KEYPAD_MINOR           185
 
@@ -1617,6 +1617,8 @@ static void panel_attach(struct parport *port)
        return;
 
 err_lcd_unreg:
+       if (scan_timer.function)
+               del_timer_sync(&scan_timer);
        if (lcd.enabled)
                charlcd_unregister(lcd.charlcd);
 err_unreg_device:
index dc40449..28b92e3 100644 (file)
@@ -202,7 +202,7 @@ config GENERIC_ARCH_TOPOLOGY
        help
          Enable support for architectures common topology code: e.g., parsing
          CPU capacity information from DT, usage of such information for
-         appropriate scaling, sysfs interface for changing capacity values at
+         appropriate scaling, sysfs interface for reading capacity values at
          runtime.
 
 endmenu
index 63c1e76..b54d241 100644 (file)
 #include <linux/string.h>
 #include <linux/sched/topology.h>
 #include <linux/cpuset.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 
 DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
 
@@ -241,3 +246,296 @@ static void parsing_done_workfn(struct work_struct *work)
 #else
 core_initcall(free_raw_capacity);
 #endif
+
+#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
+static int __init get_cpu_for_node(struct device_node *node)
+{
+       struct device_node *cpu_node;
+       int cpu;
+
+       cpu_node = of_parse_phandle(node, "cpu", 0);
+       if (!cpu_node)
+               return -1;
+
+       cpu = of_cpu_node_to_id(cpu_node);
+       if (cpu >= 0)
+               topology_parse_cpu_capacity(cpu_node, cpu);
+       else
+               pr_crit("Unable to find CPU node for %pOF\n", cpu_node);
+
+       of_node_put(cpu_node);
+       return cpu;
+}
+
+static int __init parse_core(struct device_node *core, int package_id,
+                            int core_id)
+{
+       char name[10];
+       bool leaf = true;
+       int i = 0;
+       int cpu;
+       struct device_node *t;
+
+       do {
+               snprintf(name, sizeof(name), "thread%d", i);
+               t = of_get_child_by_name(core, name);
+               if (t) {
+                       leaf = false;
+                       cpu = get_cpu_for_node(t);
+                       if (cpu >= 0) {
+                               cpu_topology[cpu].package_id = package_id;
+                               cpu_topology[cpu].core_id = core_id;
+                               cpu_topology[cpu].thread_id = i;
+                       } else {
+                               pr_err("%pOF: Can't get CPU for thread\n",
+                                      t);
+                               of_node_put(t);
+                               return -EINVAL;
+                       }
+                       of_node_put(t);
+               }
+               i++;
+       } while (t);
+
+       cpu = get_cpu_for_node(core);
+       if (cpu >= 0) {
+               if (!leaf) {
+                       pr_err("%pOF: Core has both threads and CPU\n",
+                              core);
+                       return -EINVAL;
+               }
+
+               cpu_topology[cpu].package_id = package_id;
+               cpu_topology[cpu].core_id = core_id;
+       } else if (leaf) {
+               pr_err("%pOF: Can't get CPU for leaf core\n", core);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __init parse_cluster(struct device_node *cluster, int depth)
+{
+       char name[10];
+       bool leaf = true;
+       bool has_cores = false;
+       struct device_node *c;
+       static int package_id __initdata;
+       int core_id = 0;
+       int i, ret;
+
+       /*
+        * First check for child clusters; we currently ignore any
+        * information about the nesting of clusters and present the
+        * scheduler with a flat list of them.
+        */
+       i = 0;
+       do {
+               snprintf(name, sizeof(name), "cluster%d", i);
+               c = of_get_child_by_name(cluster, name);
+               if (c) {
+                       leaf = false;
+                       ret = parse_cluster(c, depth + 1);
+                       of_node_put(c);
+                       if (ret != 0)
+                               return ret;
+               }
+               i++;
+       } while (c);
+
+       /* Now check for cores */
+       i = 0;
+       do {
+               snprintf(name, sizeof(name), "core%d", i);
+               c = of_get_child_by_name(cluster, name);
+               if (c) {
+                       has_cores = true;
+
+                       if (depth == 0) {
+                               pr_err("%pOF: cpu-map children should be clusters\n",
+                                      c);
+                               of_node_put(c);
+                               return -EINVAL;
+                       }
+
+                       if (leaf) {
+                               ret = parse_core(c, package_id, core_id++);
+                       } else {
+                               pr_err("%pOF: Non-leaf cluster with core %s\n",
+                                      cluster, name);
+                               ret = -EINVAL;
+                       }
+
+                       of_node_put(c);
+                       if (ret != 0)
+                               return ret;
+               }
+               i++;
+       } while (c);
+
+       if (leaf && !has_cores)
+               pr_warn("%pOF: empty cluster\n", cluster);
+
+       if (leaf)
+               package_id++;
+
+       return 0;
+}
+
+static int __init parse_dt_topology(void)
+{
+       struct device_node *cn, *map;
+       int ret = 0;
+       int cpu;
+
+       cn = of_find_node_by_path("/cpus");
+       if (!cn) {
+               pr_err("No CPU information found in DT\n");
+               return 0;
+       }
+
+       /*
+        * When topology is provided cpu-map is essentially a root
+        * cluster with restricted subnodes.
+        */
+       map = of_get_child_by_name(cn, "cpu-map");
+       if (!map)
+               goto out;
+
+       ret = parse_cluster(map, 0);
+       if (ret != 0)
+               goto out_map;
+
+       topology_normalize_cpu_scale();
+
+       /*
+        * Check that all cores are in the topology; the SMP code will
+        * only mark cores described in the DT as possible.
+        */
+       for_each_possible_cpu(cpu)
+               if (cpu_topology[cpu].package_id == -1)
+                       ret = -EINVAL;
+
+out_map:
+       of_node_put(map);
+out:
+       of_node_put(cn);
+       return ret;
+}
+#endif
+
+/*
+ * cpu topology table
+ */
+struct cpu_topology cpu_topology[NR_CPUS];
+EXPORT_SYMBOL_GPL(cpu_topology);
+
+const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+       const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
+
+       /* Find the smaller of NUMA, core or LLC siblings */
+       if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
+               /* not numa in package, lets use the package siblings */
+               core_mask = &cpu_topology[cpu].core_sibling;
+       }
+       if (cpu_topology[cpu].llc_id != -1) {
+               if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask))
+                       core_mask = &cpu_topology[cpu].llc_sibling;
+       }
+
+       return core_mask;
+}
+
+void update_siblings_masks(unsigned int cpuid)
+{
+       struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
+       int cpu;
+
+       /* update core and thread sibling masks */
+       for_each_online_cpu(cpu) {
+               cpu_topo = &cpu_topology[cpu];
+
+               if (cpuid_topo->llc_id == cpu_topo->llc_id) {
+                       cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling);
+                       cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling);
+               }
+
+               if (cpuid_topo->package_id != cpu_topo->package_id)
+                       continue;
+
+               cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+               cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
+
+               if (cpuid_topo->core_id != cpu_topo->core_id)
+                       continue;
+
+               cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
+               cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
+       }
+}
+
+static void clear_cpu_topology(int cpu)
+{
+       struct cpu_topology *cpu_topo = &cpu_topology[cpu];
+
+       cpumask_clear(&cpu_topo->llc_sibling);
+       cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);
+
+       cpumask_clear(&cpu_topo->core_sibling);
+       cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
+       cpumask_clear(&cpu_topo->thread_sibling);
+       cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
+}
+
+void __init reset_cpu_topology(void)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu) {
+               struct cpu_topology *cpu_topo = &cpu_topology[cpu];
+
+               cpu_topo->thread_id = -1;
+               cpu_topo->core_id = -1;
+               cpu_topo->package_id = -1;
+               cpu_topo->llc_id = -1;
+
+               clear_cpu_topology(cpu);
+       }
+}
+
+void remove_cpu_topology(unsigned int cpu)
+{
+       int sibling;
+
+       for_each_cpu(sibling, topology_core_cpumask(cpu))
+               cpumask_clear_cpu(cpu, topology_core_cpumask(sibling));
+       for_each_cpu(sibling, topology_sibling_cpumask(cpu))
+               cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
+       for_each_cpu(sibling, topology_llc_cpumask(cpu))
+               cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling));
+
+       clear_cpu_topology(cpu);
+}
+
+__weak int __init parse_acpi_topology(void)
+{
+       return 0;
+}
+
+#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
+void __init init_cpu_topology(void)
+{
+       reset_cpu_topology();
+
+       /*
+        * Discard anything that was parsed if we hit an error so we
+        * don't use partial information.
+        */
+       if (parse_acpi_topology())
+               reset_cpu_topology();
+       else if (of_have_populated_dt() && parse_dt_topology())
+               reset_cpu_topology();
+}
+#endif
index a498413..0fd6f97 100644 (file)
@@ -44,7 +44,7 @@ config REGMAP_IRQ
 
 config REGMAP_SOUNDWIRE
        tristate
-       depends on SOUNDWIRE_BUS
+       depends on SOUNDWIRE
 
 config REGMAP_SCCB
        tristate
index e5e1b3a..e72843f 100644 (file)
@@ -588,14 +588,6 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
        }
 
        map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
-       if (!map->debugfs) {
-               dev_warn(map->dev,
-                        "Failed to create %s debugfs directory\n", name);
-
-               kfree(map->debugfs_name);
-               map->debugfs_name = NULL;
-               return;
-       }
 
        debugfs_create_file("name", 0400, map->debugfs,
                            map, &regmap_name_fops);
@@ -672,10 +664,6 @@ void regmap_debugfs_initcall(void)
        struct regmap_debugfs_node *node, *tmp;
 
        regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
-       if (!regmap_debugfs_root) {
-               pr_warn("regmap: Failed to create debugfs root\n");
-               return;
-       }
 
        mutex_lock(&regmap_debugfs_early_lock);
        list_for_each_entry_safe(node, tmp, &regmap_debugfs_early_list, link) {
index c9dc70c..3d64c93 100644 (file)
@@ -370,7 +370,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret < 0) {
                        dev_err(map->dev, "IRQ thread failed to resume: %d\n",
                                ret);
-                       pm_runtime_put(map->dev);
                        goto exit;
                }
        }
@@ -425,8 +424,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                        dev_err(map->dev,
                                                "Failed to read IRQ status %d\n",
                                                ret);
-                                       if (chip->runtime_pm)
-                                               pm_runtime_put(map->dev);
                                        goto exit;
                                }
                        }
@@ -478,8 +475,6 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                dev_err(map->dev,
                                        "Failed to read IRQ status: %d\n",
                                        ret);
-                               if (chip->runtime_pm)
-                                       pm_runtime_put(map->dev);
                                goto exit;
                        }
                }
@@ -513,10 +508,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+exit:
        if (chip->runtime_pm)
                pm_runtime_put(map->dev);
 
-exit:
        if (chip->handle_post_irq)
                chip->handle_post_irq(chip->irq_drv_data);
 
index 9bd4ddd..5b24876 100644 (file)
@@ -322,6 +322,8 @@ static int drbd_thread_setup(void *arg)
                 thi->name[0],
                 resource->name);
 
+       allow_kernel_signal(DRBD_SIGKILL);
+       allow_kernel_signal(SIGXCPU);
 restart:
        retval = thi->function(thi);
 
index 3327192..c8fb886 100644 (file)
@@ -3038,6 +3038,17 @@ again:
                }
                return true;
        case RBD_OBJ_READ_PARENT:
+               /*
+                * The parent image is read only up to the overlap -- zero-fill
+                * from the overlap to the end of the request.
+                */
+               if (!*result) {
+                       u32 obj_overlap = rbd_obj_img_extents_bytes(obj_req);
+
+                       if (obj_overlap < obj_req->ex.oe_len)
+                               rbd_obj_zero_range(obj_req, obj_overlap,
+                                           obj_req->ex.oe_len - obj_overlap);
+               }
                return true;
        default:
                BUG();
index 3ac6a5d..b90dbcd 100644 (file)
@@ -965,6 +965,7 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir)
                }
        }
 
+       err = -ENOMEM;
        for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) {
                req = kzalloc(sizeof(*req), GFP_KERNEL);
                if (!req)
@@ -987,7 +988,7 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir)
        err = xen_blkif_map(ring, ring_ref, nr_grefs, evtchn);
        if (err) {
                xenbus_dev_fatal(dev, err, "mapping ring-ref port %u", evtchn);
-               return err;
+               goto fail;
        }
 
        return 0;
@@ -1007,8 +1008,7 @@ fail:
                }
                kfree(req);
        }
-       return -ENOMEM;
-
+       return err;
 }
 
 static int connect_ring(struct backend_info *be)
index a0e8453..1fa58c0 100644 (file)
@@ -337,7 +337,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 
        usb_free_urb(urb);
 
-       return 0;
+       return err;
 }
 
 static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
index 8b33128..0875470 100644 (file)
@@ -99,6 +99,27 @@ static int qca_send_reset(struct hci_dev *hdev)
        return 0;
 }
 
+int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       int err;
+
+       bt_dev_dbg(hdev, "QCA pre shutdown cmd");
+
+       skb = __hci_cmd_sync(hdev, QCA_PRE_SHUTDOWN_CMD, 0,
+                               NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               bt_dev_err(hdev, "QCA preshutdown_cmd failed (%d)", err);
+               return err;
+       }
+
+       kfree_skb(skb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
+
 static void qca_tlv_check_data(struct rome_config *config,
                                const struct firmware *fw)
 {
@@ -119,6 +140,7 @@ static void qca_tlv_check_data(struct rome_config *config,
        BT_DBG("Length\t\t : %d bytes", length);
 
        config->dnld_mode = ROME_SKIP_EVT_NONE;
+       config->dnld_type = ROME_SKIP_EVT_NONE;
 
        switch (config->type) {
        case TLV_TYPE_PATCH:
@@ -268,7 +290,7 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
 
        evt = skb_put(skb, sizeof(*evt));
        evt->ncmd = 1;
-       evt->opcode = QCA_HCI_CC_OPCODE;
+       evt->opcode = cpu_to_le16(QCA_HCI_CC_OPCODE);
 
        skb_put_u8(skb, QCA_HCI_CC_SUCCESS);
 
@@ -323,7 +345,7 @@ static int qca_download_firmware(struct hci_dev *hdev,
         */
        if (config->dnld_type == ROME_SKIP_EVT_VSE_CC ||
            config->dnld_type == ROME_SKIP_EVT_VSE)
-               return qca_inject_cmd_complete_event(hdev);
+               ret = qca_inject_cmd_complete_event(hdev);
 
 out:
        release_firmware(fw);
@@ -388,6 +410,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
                return err;
        }
 
+       /* Give the controller some time to get ready to receive the NVM */
+       msleep(10);
+
        /* Download NVM configuration */
        config.type = TLV_TYPE_NVM;
        if (firmware_name)
index 6a291a7..69c5315 100644 (file)
@@ -13,6 +13,7 @@
 #define EDL_PATCH_TLV_REQ_CMD          (0x1E)
 #define EDL_NVM_ACCESS_SET_REQ_CMD     (0x01)
 #define MAX_SIZE_PER_TLV_SEGMENT       (243)
+#define QCA_PRE_SHUTDOWN_CMD           (0xFC08)
 
 #define EDL_CMD_REQ_RES_EVT            (0x00)
 #define EDL_PATCH_VER_RES_EVT          (0x19)
@@ -135,6 +136,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
                   const char *firmware_name);
 int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
 int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
 static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
 {
        return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3998;
@@ -167,4 +169,9 @@ static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
 {
        return false;
 }
+
+static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
+{
+       return -EOPNOTSUPP;
+}
 #endif
index 3876fee..ba41490 100644 (file)
@@ -384,6 +384,9 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x13d3, 0x3526), .driver_info = BTUSB_REALTEK },
        { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
 
+       /* Additional Realtek 8822CE Bluetooth devices */
+       { USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK },
+
        /* Silicon Wave based devices */
        { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
 
@@ -1170,10 +1173,6 @@ static int btusb_open(struct hci_dev *hdev)
        }
 
        data->intf->needs_remote_wakeup = 1;
-       /* device specific wakeup source enabled and required for USB
-        * remote wakeup while host is suspended
-        */
-       device_wakeup_enable(&data->udev->dev);
 
        if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
                goto done;
@@ -1238,7 +1237,6 @@ static int btusb_close(struct hci_dev *hdev)
                goto failed;
 
        data->intf->needs_remote_wakeup = 0;
-       device_wakeup_disable(&data->udev->dev);
        usb_autopm_put_interface(data->intf);
 
 failed:
@@ -2762,8 +2760,10 @@ static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
        fw_size = fw->size;
 
        /* The size of patch header is 30 bytes, should be skip */
-       if (fw_size < 30)
+       if (fw_size < 30) {
+               err = -EINVAL;
                goto err_release_fw;
+       }
 
        fw_size -= 30;
        fw_ptr += 30;
index 82a0a36..31dec43 100644 (file)
@@ -309,13 +309,14 @@ static void qca_wq_awake_device(struct work_struct *work)
                                            ws_awake_device);
        struct hci_uart *hu = qca->hu;
        unsigned long retrans_delay;
+       unsigned long flags;
 
        BT_DBG("hu %p wq awake device", hu);
 
        /* Vote for serial clock */
        serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
 
-       spin_lock(&qca->hci_ibs_lock);
+       spin_lock_irqsave(&qca->hci_ibs_lock, flags);
 
        /* Send wake indication to device */
        if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
@@ -327,7 +328,7 @@ static void qca_wq_awake_device(struct work_struct *work)
        retrans_delay = msecs_to_jiffies(qca->wake_retrans);
        mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay);
 
-       spin_unlock(&qca->hci_ibs_lock);
+       spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
 
        /* Actually send the packets */
        hci_uart_tx_wakeup(hu);
@@ -338,12 +339,13 @@ static void qca_wq_awake_rx(struct work_struct *work)
        struct qca_data *qca = container_of(work, struct qca_data,
                                            ws_awake_rx);
        struct hci_uart *hu = qca->hu;
+       unsigned long flags;
 
        BT_DBG("hu %p wq awake rx", hu);
 
        serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
 
-       spin_lock(&qca->hci_ibs_lock);
+       spin_lock_irqsave(&qca->hci_ibs_lock, flags);
        qca->rx_ibs_state = HCI_IBS_RX_AWAKE;
 
        /* Always acknowledge device wake up,
@@ -354,7 +356,7 @@ static void qca_wq_awake_rx(struct work_struct *work)
 
        qca->ibs_sent_wacks++;
 
-       spin_unlock(&qca->hci_ibs_lock);
+       spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
 
        /* Actually send the packets */
        hci_uart_tx_wakeup(hu);
@@ -705,7 +707,7 @@ static void device_want_to_sleep(struct hci_uart *hu)
        unsigned long flags;
        struct qca_data *qca = hu->priv;
 
-       BT_DBG("hu %p want to sleep", hu);
+       BT_DBG("hu %p want to sleep in %d state", hu, qca->rx_ibs_state);
 
        spin_lock_irqsave(&qca->hci_ibs_lock, flags);
 
@@ -720,7 +722,7 @@ static void device_want_to_sleep(struct hci_uart *hu)
                break;
 
        case HCI_IBS_RX_ASLEEP:
-               /* Fall through */
+               break;
 
        default:
                /* Any other state is illegal */
@@ -912,7 +914,7 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
                if (hdr->evt == HCI_EV_VENDOR)
                        complete(&qca->drop_ev_comp);
 
-               kfree(skb);
+               kfree_skb(skb);
 
                return 0;
        }
@@ -1386,6 +1388,9 @@ static int qca_power_off(struct hci_dev *hdev)
 {
        struct hci_uart *hu = hci_get_drvdata(hdev);
 
+       /* Perform pre shutdown command */
+       qca_send_pre_shutdown_cmd(hdev);
+
        qca_power_shutdown(hu);
        return 0;
 }
index 19d7b6f..20c9571 100644 (file)
@@ -456,6 +456,17 @@ struct hisi_lpc_acpi_cell {
        size_t pdata_size;
 };
 
+static void hisi_lpc_acpi_remove(struct device *hostdev)
+{
+       struct acpi_device *adev = ACPI_COMPANION(hostdev);
+       struct acpi_device *child;
+
+       device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev);
+
+       list_for_each_entry(child, &adev->children, node)
+               acpi_device_clear_enumerated(child);
+}
+
 /*
  * hisi_lpc_acpi_probe - probe children for ACPI FW
  * @hostdev: LPC host device pointer
@@ -555,8 +566,7 @@ static int hisi_lpc_acpi_probe(struct device *hostdev)
        return 0;
 
 fail:
-       device_for_each_child(hostdev, NULL,
-                             hisi_lpc_acpi_remove_subdev);
+       hisi_lpc_acpi_remove(hostdev);
        return ret;
 }
 
@@ -569,6 +579,10 @@ static int hisi_lpc_acpi_probe(struct device *dev)
 {
        return -ENODEV;
 }
+
+static void hisi_lpc_acpi_remove(struct device *hostdev)
+{
+}
 #endif // CONFIG_ACPI
 
 /*
@@ -606,24 +620,27 @@ static int hisi_lpc_probe(struct platform_device *pdev)
        range->fwnode = dev->fwnode;
        range->flags = LOGIC_PIO_INDIRECT;
        range->size = PIO_INDIRECT_SIZE;
+       range->hostdata = lpcdev;
+       range->ops = &hisi_lpc_ops;
+       lpcdev->io_host = range;
 
        ret = logic_pio_register_range(range);
        if (ret) {
                dev_err(dev, "register IO range failed (%d)!\n", ret);
                return ret;
        }
-       lpcdev->io_host = range;
 
        /* register the LPC host PIO resources */
        if (acpi_device)
                ret = hisi_lpc_acpi_probe(dev);
        else
                ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
-       if (ret)
+       if (ret) {
+               logic_pio_unregister_range(range);
                return ret;
+       }
 
-       lpcdev->io_host->hostdata = lpcdev;
-       lpcdev->io_host->ops = &hisi_lpc_ops;
+       dev_set_drvdata(dev, lpcdev);
 
        io_end = lpcdev->io_host->io_start + lpcdev->io_host->size;
        dev_info(dev, "registered range [%pa - %pa]\n",
@@ -632,6 +649,23 @@ static int hisi_lpc_probe(struct platform_device *pdev)
        return ret;
 }
 
+static int hisi_lpc_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acpi_device *acpi_device = ACPI_COMPANION(dev);
+       struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev);
+       struct logic_pio_hwaddr *range = lpcdev->io_host;
+
+       if (acpi_device)
+               hisi_lpc_acpi_remove(dev);
+       else
+               of_platform_depopulate(dev);
+
+       logic_pio_unregister_range(range);
+
+       return 0;
+}
+
 static const struct of_device_id hisi_lpc_of_match[] = {
        { .compatible = "hisilicon,hip06-lpc", },
        { .compatible = "hisilicon,hip07-lpc", },
@@ -645,5 +679,6 @@ static struct platform_driver hisi_lpc_driver = {
                .acpi_match_table = ACPI_PTR(hisi_lpc_acpi_match),
        },
        .probe = hisi_lpc_probe,
+       .remove = hisi_lpc_remove,
 };
 builtin_platform_driver(hisi_lpc_driver);
index e6deabd..2db474a 100644 (file)
@@ -949,7 +949,7 @@ static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
                *best_mode = SYSC_IDLE_SMART_WKUP;
        else if (idlemodes & BIT(SYSC_IDLE_SMART))
                *best_mode = SYSC_IDLE_SMART;
-       else if (idlemodes & SYSC_IDLE_FORCE)
+       else if (idlemodes & BIT(SYSC_IDLE_FORCE))
                *best_mode = SYSC_IDLE_FORCE;
        else
                return -EINVAL;
@@ -1267,7 +1267,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
        SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
                   0xffff00f0, 0),
-       SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
+       SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0xa3170504, 0xffffffff, 0),
+       SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0x4edb1902, 0xffffffff, 0),
        SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
        SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
        SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
@@ -1692,10 +1693,7 @@ static int sysc_init_sysc_mask(struct sysc *ddata)
        if (error)
                return 0;
 
-       if (val)
-               ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
-       else
-               ddata->cfg.sysc_val = ddata->cap->sysc_mask;
+       ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
 
        return 0;
 }
@@ -2385,27 +2383,27 @@ static int sysc_probe(struct platform_device *pdev)
 
        error = sysc_init_dts_quirks(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        error = sysc_map_and_check_registers(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        error = sysc_init_sysc_mask(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        error = sysc_init_idlemodes(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        error = sysc_init_syss_mask(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        error = sysc_init_pdata(ddata);
        if (error)
-               goto unprepare;
+               return error;
 
        sysc_init_early_quirks(ddata);
 
@@ -2415,7 +2413,7 @@ static int sysc_probe(struct platform_device *pdev)
 
        error = sysc_init_resets(ddata);
        if (error)
-               return error;
+               goto unprepare;
 
        error = sysc_init_module(ddata);
        if (error)
index 3e86688..df0fc99 100644 (file)
@@ -26,28 +26,6 @@ config DEVKMEM
          kind of kernel debugging operations.
          When in doubt, say "N".
 
-config SGI_SNSC
-       bool "SGI Altix system controller communication support"
-       depends on (IA64_SGI_SN2 || IA64_GENERIC)
-       help
-         If you have an SGI Altix and you want to enable system
-         controller communication from user space (you want this!),
-         say Y.  Otherwise, say N.
-
-config SGI_TIOCX
-       bool "SGI TIO CX driver support"
-       depends on (IA64_SGI_SN2 || IA64_GENERIC)
-       help
-         If you have an SGI Altix and you have fpga devices attached
-         to your TIO, say Y here, otherwise say N.
-
-config SGI_MBCS
-       tristate "SGI FPGA Core Services driver support"
-       depends on SGI_TIOCX
-       help
-         If you have an SGI Altix with an attached SABrick
-         say Y or M here, otherwise say N.
-
 source "drivers/tty/serial/Kconfig"
 source "drivers/tty/serdev/Kconfig"
 
@@ -573,3 +551,12 @@ config RANDOM_TRUST_CPU
        has not installed a hidden back door to compromise the CPU's
        random number generation facilities. This can also be configured
        at boot with "random.trust_cpu=on/off".
+
+config RANDOM_TRUST_BOOTLOADER
+       bool "Trust the bootloader to initialize Linux's CRNG"
+       help
+       Some bootloaders can provide entropy to increase the kernel's initial
+       device randomness. Say Y here to assume the entropy provided by the
+       booloader is trustworthy so it will be added to the kernel's entropy
+       pool. Otherwise, say N here so it will be regarded as device input that
+       only mixes the entropy pool.
\ No newline at end of file
index fbea7dd..7c5ea6f 100644 (file)
@@ -9,11 +9,9 @@ obj-y                          += misc.o
 obj-$(CONFIG_ATARI_DSP56K)     += dsp56k.o
 obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
-obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)            += mspec.o
 obj-$(CONFIG_UV_MMTIMER)       += uv_mmtimer.o
 obj-$(CONFIG_IBM_BSR)          += bsr.o
-obj-$(CONFIG_SGI_MBCS)         += mbcs.o
 
 obj-$(CONFIG_PRINTER)          += lp.o
 
index 6231714..812d6aa 100644 (file)
@@ -111,14 +111,14 @@ config AGP_VIA
 
 config AGP_I460
        tristate "Intel 460GX chipset support"
-       depends on AGP && (IA64_DIG || IA64_GENERIC)
+       depends on AGP && IA64
        help
          This option gives you AGP GART support for the Intel 460GX chipset
          for IA64 processors.
 
 config AGP_HP_ZX1
        tristate "HP ZX1 chipset AGP support"
-       depends on AGP && (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC)
+       depends on AGP && IA64
        help
          This option gives you AGP GART support for the HP ZX1 chipset
          for IA64 processors.
@@ -150,13 +150,6 @@ config AGP_EFFICEON
          This option gives you AGP support for the Transmeta Efficeon
          series processors with integrated northbridges.
 
-config AGP_SGI_TIOCA
-        tristate "SGI TIO chipset AGP support"
-        depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
-        help
-          This option gives you AGP GART support for the SGI TIO chipset
-          for IA64 processors.
-
 config INTEL_GTT
        tristate
        depends on X86 && PCI
index 4a786ff..cb2497d 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_AGP_I460)                += i460-agp.o
 obj-$(CONFIG_AGP_INTEL)                += intel-agp.o
 obj-$(CONFIG_INTEL_GTT)                += intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)       += nvidia-agp.o
-obj-$(CONFIG_AGP_SGI_TIOCA)    += sgi-agp.o
 obj-$(CONFIG_AGP_SIS)          += sis-agp.o
 obj-$(CONFIG_AGP_SWORKS)       += sworks-agp.o
 obj-$(CONFIG_AGP_UNINORTH)     += uninorth-agp.o
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
deleted file mode 100644 (file)
index e7d5bdc..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * SGI TIOCA AGPGART routines.
- *
- */
-
-#include <linux/acpi.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/agp_backend.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/tioca_provider.h>
-#include "agp.h"
-
-extern int agp_memory_reserved;
-extern uint32_t tioca_gart_found;
-extern struct list_head tioca_list;
-static struct agp_bridge_data **sgi_tioca_agp_bridges;
-
-/*
- * The aperature size and related information is set up at TIOCA init time.
- * Values for this table will be extracted and filled in at
- * sgi_tioca_fetch_size() time.
- */
-
-static struct aper_size_info_fixed sgi_tioca_sizes[] = {
-       {0, 0, 0},
-};
-
-static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
-{
-       struct page *page;
-       int nid;
-       struct tioca_kernel *info =
-           (struct tioca_kernel *)bridge->dev_private_data;
-
-       nid = info->ca_closest_node;
-       page = alloc_pages_node(nid, GFP_KERNEL, 0);
-       if (!page)
-               return NULL;
-
-       get_page(page);
-       atomic_inc(&agp_bridge->current_memory_agp);
-       return page;
-}
-
-/*
- * Flush GART tlb's.  Cannot selectively flush based on memory so the mem
- * arg is ignored.
- */
-
-static void sgi_tioca_tlbflush(struct agp_memory *mem)
-{
-       tioca_tlbflush(mem->bridge->dev_private_data);
-}
-
-/*
- * Given an address of a host physical page, turn it into a valid gart
- * entry.
- */
-static unsigned long
-sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
-                     int type)
-{
-       return tioca_physpage_to_gart(addr);
-}
-
-static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
-{
-       tioca_fastwrite_enable(bridge->dev_private_data);
-}
-
-/*
- * sgi_tioca_configure() doesn't have anything to do since the base CA driver
- * has alreay set up the GART.
- */
-
-static int sgi_tioca_configure(void)
-{
-       return 0;
-}
-
-/*
- * Determine gfx aperature size.  This has already been determined by the
- * CA driver init, so just need to set agp_bridge values accordingly.
- */
-
-static int sgi_tioca_fetch_size(void)
-{
-       struct tioca_kernel *info =
-           (struct tioca_kernel *)agp_bridge->dev_private_data;
-
-       sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
-       sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
-
-       return sgi_tioca_sizes[0].size;
-}
-
-static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       struct tioca_kernel *info =
-           (struct tioca_kernel *)bridge->dev_private_data;
-
-       bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
-       bridge->gatt_table = bridge->gatt_table_real;
-       bridge->gatt_bus_addr = info->ca_gfxgart_base;
-
-       return 0;
-}
-
-static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
-{
-       return 0;
-}
-
-static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
-                                  int type)
-{
-       int num_entries;
-       size_t i;
-       off_t j;
-       void *temp;
-       struct agp_bridge_data *bridge;
-       u64 *table;
-
-       bridge = mem->bridge;
-       if (!bridge)
-               return -EINVAL;
-
-       table = (u64 *)bridge->gatt_table;
-
-       temp = bridge->current_size;
-
-       switch (bridge->driver->size_type) {
-       case U8_APER_SIZE:
-               num_entries = A_SIZE_8(temp)->num_entries;
-               break;
-       case U16_APER_SIZE:
-               num_entries = A_SIZE_16(temp)->num_entries;
-               break;
-       case U32_APER_SIZE:
-               num_entries = A_SIZE_32(temp)->num_entries;
-               break;
-       case FIXED_APER_SIZE:
-               num_entries = A_SIZE_FIX(temp)->num_entries;
-               break;
-       case LVL2_APER_SIZE:
-               return -EINVAL;
-       default:
-               num_entries = 0;
-               break;
-       }
-
-       num_entries -= agp_memory_reserved / PAGE_SIZE;
-       if (num_entries < 0)
-               num_entries = 0;
-
-       if (type != 0 || mem->type != 0) {
-               return -EINVAL;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               return -EINVAL;
-
-       j = pg_start;
-
-       while (j < (pg_start + mem->page_count)) {
-               if (table[j])
-                       return -EBUSY;
-               j++;
-       }
-
-       if (!mem->is_flushed) {
-               bridge->driver->cache_flush();
-               mem->is_flushed = true;
-       }
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               table[j] =
-                   bridge->driver->mask_memory(bridge,
-                                               page_to_phys(mem->pages[i]),
-                                               mem->type);
-       }
-
-       bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
-                                  int type)
-{
-       size_t i;
-       struct agp_bridge_data *bridge;
-       u64 *table;
-
-       bridge = mem->bridge;
-       if (!bridge)
-               return -EINVAL;
-
-       if (type != 0 || mem->type != 0) {
-               return -EINVAL;
-       }
-
-       table = (u64 *)bridge->gatt_table;
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               table[i] = 0;
-       }
-
-       bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-static void sgi_tioca_cache_flush(void)
-{
-}
-
-/*
- * Cleanup.  Nothing to do as the CA driver owns the GART.
- */
-
-static void sgi_tioca_cleanup(void)
-{
-}
-
-static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
-{
-       struct agp_bridge_data *bridge;
-
-       list_for_each_entry(bridge, &agp_bridges, list) {
-               if (bridge->dev->bus == pdev->bus)
-                       break;
-       }
-       return bridge;
-}
-
-const struct agp_bridge_driver sgi_tioca_driver = {
-       .owner = THIS_MODULE,
-       .size_type = U16_APER_SIZE,
-       .configure = sgi_tioca_configure,
-       .fetch_size = sgi_tioca_fetch_size,
-       .cleanup = sgi_tioca_cleanup,
-       .tlb_flush = sgi_tioca_tlbflush,
-       .mask_memory = sgi_tioca_mask_memory,
-       .agp_enable = sgi_tioca_agp_enable,
-       .cache_flush = sgi_tioca_cache_flush,
-       .create_gatt_table = sgi_tioca_create_gatt_table,
-       .free_gatt_table = sgi_tioca_free_gatt_table,
-       .insert_memory = sgi_tioca_insert_memory,
-       .remove_memory = sgi_tioca_remove_memory,
-       .alloc_by_type = agp_generic_alloc_by_type,
-       .free_by_type = agp_generic_free_by_type,
-       .agp_alloc_page = sgi_tioca_alloc_page,
-       .agp_destroy_page = agp_generic_destroy_page,
-       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
-       .cant_use_aperture = true,
-       .needs_scratch_page = false,
-       .num_aperture_sizes = 1,
-};
-
-static int agp_sgi_init(void)
-{
-       unsigned int j;
-       struct tioca_kernel *info;
-       struct pci_dev *pdev = NULL;
-
-       if (tioca_gart_found)
-               printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
-       else
-               return 0;
-
-       sgi_tioca_agp_bridges = kmalloc_array(tioca_gart_found,
-                                             sizeof(struct agp_bridge_data *),
-                                             GFP_KERNEL);
-       if (!sgi_tioca_agp_bridges)
-               return -ENOMEM;
-
-       j = 0;
-       list_for_each_entry(info, &tioca_list, ca_list) {
-               if (list_empty(info->ca_devices))
-                       continue;
-               list_for_each_entry(pdev, info->ca_devices, bus_list) {
-                       u8 cap_ptr;
-
-                       if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
-                               continue;
-                       cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
-                       if (!cap_ptr)
-                               continue;
-               }
-               sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
-               printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
-                      sgi_tioca_agp_bridges[j]);
-               if (sgi_tioca_agp_bridges[j]) {
-                       sgi_tioca_agp_bridges[j]->dev = pdev;
-                       sgi_tioca_agp_bridges[j]->dev_private_data = info;
-                       sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
-                       sgi_tioca_agp_bridges[j]->gart_bus_addr =
-                           info->ca_gfxap_base;
-                       sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */
-                           (0x1 << 9) |        /* SBA supported */
-                           (0x1 << 5) |        /* 64-bit addresses supported */
-                           (0x1 << 4) |        /* FW supported */
-                           (0x1 << 3) |        /* AGP 3.0 mode */
-                           0x2;        /* 8x transfer only */
-                       sgi_tioca_agp_bridges[j]->current_size =
-                           sgi_tioca_agp_bridges[j]->previous_size =
-                           (void *)&sgi_tioca_sizes[0];
-                       agp_add_bridge(sgi_tioca_agp_bridges[j]);
-               }
-               j++;
-       }
-
-       agp_find_bridge = &sgi_tioca_find_bridge;
-       return 0;
-}
-
-static void agp_sgi_cleanup(void)
-{
-       kfree(sgi_tioca_agp_bridges);
-       sgi_tioca_agp_bridges = NULL;
-}
-
-module_init(agp_sgi_init);
-module_exit(agp_sgi_cleanup);
-
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
deleted file mode 100644 (file)
index 0a31b60..0000000
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
- */
-
-/*
- *     MOATB Core Services driver.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/uio.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <asm/io.h>
-#include <linux/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/tiocx.h>
-#include "mbcs.h"
-
-#define MBCS_DEBUG 0
-#if MBCS_DEBUG
-#define DBG(fmt...)    printk(KERN_ALERT fmt)
-#else
-#define DBG(fmt...)
-#endif
-static DEFINE_MUTEX(mbcs_mutex);
-static int mbcs_major;
-
-static LIST_HEAD(soft_list);
-
-/*
- * file operations
- */
-static const struct file_operations mbcs_ops = {
-       .owner = THIS_MODULE,
-       .open = mbcs_open,
-       .llseek = mbcs_sram_llseek,
-       .read = mbcs_sram_read,
-       .write = mbcs_sram_write,
-       .mmap = mbcs_gscr_mmap,
-};
-
-struct mbcs_callback_arg {
-       int minor;
-       struct cx_dev *cx_dev;
-};
-
-static inline void mbcs_getdma_init(struct getdma *gdma)
-{
-       memset(gdma, 0, sizeof(struct getdma));
-       gdma->DoneIntEnable = 1;
-}
-
-static inline void mbcs_putdma_init(struct putdma *pdma)
-{
-       memset(pdma, 0, sizeof(struct putdma));
-       pdma->DoneIntEnable = 1;
-}
-
-static inline void mbcs_algo_init(struct algoblock *algo_soft)
-{
-       memset(algo_soft, 0, sizeof(struct algoblock));
-}
-
-static inline void mbcs_getdma_set(void *mmr,
-                      uint64_t hostAddr,
-                      uint64_t localAddr,
-                      uint64_t localRamSel,
-                      uint64_t numPkts,
-                      uint64_t amoEnable,
-                      uint64_t intrEnable,
-                      uint64_t peerIO,
-                      uint64_t amoHostDest,
-                      uint64_t amoModType, uint64_t intrHostDest,
-                      uint64_t intrVector)
-{
-       union dma_control rdma_control;
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union dma_localaddr local_addr;
-       union dma_hostaddr host_addr;
-
-       rdma_control.dma_control_reg = 0;
-       amo_dest.dma_amo_dest_reg = 0;
-       intr_dest.intr_dest_reg = 0;
-       local_addr.dma_localaddr_reg = 0;
-       host_addr.dma_hostaddr_reg = 0;
-
-       host_addr.dma_sys_addr = hostAddr;
-       MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
-
-       local_addr.dma_ram_addr = localAddr;
-       local_addr.dma_ram_sel = localRamSel;
-       MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
-
-       rdma_control.dma_op_length = numPkts;
-       rdma_control.done_amo_en = amoEnable;
-       rdma_control.done_int_en = intrEnable;
-       rdma_control.pio_mem_n = peerIO;
-       MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg);
-
-       amo_dest.dma_amo_sys_addr = amoHostDest;
-       amo_dest.dma_amo_mod_type = amoModType;
-       MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
-       intr_dest.address = intrHostDest;
-       intr_dest.int_vector = intrVector;
-       MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg);
-
-}
-
-static inline void mbcs_putdma_set(void *mmr,
-                      uint64_t hostAddr,
-                      uint64_t localAddr,
-                      uint64_t localRamSel,
-                      uint64_t numPkts,
-                      uint64_t amoEnable,
-                      uint64_t intrEnable,
-                      uint64_t peerIO,
-                      uint64_t amoHostDest,
-                      uint64_t amoModType,
-                      uint64_t intrHostDest, uint64_t intrVector)
-{
-       union dma_control wdma_control;
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union dma_localaddr local_addr;
-       union dma_hostaddr host_addr;
-
-       wdma_control.dma_control_reg = 0;
-       amo_dest.dma_amo_dest_reg = 0;
-       intr_dest.intr_dest_reg = 0;
-       local_addr.dma_localaddr_reg = 0;
-       host_addr.dma_hostaddr_reg = 0;
-
-       host_addr.dma_sys_addr = hostAddr;
-       MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
-
-       local_addr.dma_ram_addr = localAddr;
-       local_addr.dma_ram_sel = localRamSel;
-       MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
-
-       wdma_control.dma_op_length = numPkts;
-       wdma_control.done_amo_en = amoEnable;
-       wdma_control.done_int_en = intrEnable;
-       wdma_control.pio_mem_n = peerIO;
-       MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg);
-
-       amo_dest.dma_amo_sys_addr = amoHostDest;
-       amo_dest.dma_amo_mod_type = amoModType;
-       MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
-       intr_dest.address = intrHostDest;
-       intr_dest.int_vector = intrVector;
-       MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg);
-
-}
-
-static inline void mbcs_algo_set(void *mmr,
-                    uint64_t amoHostDest,
-                    uint64_t amoModType,
-                    uint64_t intrHostDest,
-                    uint64_t intrVector, uint64_t algoStepCount)
-{
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union algo_step step;
-
-       step.algo_step_reg = 0;
-       intr_dest.intr_dest_reg = 0;
-       amo_dest.dma_amo_dest_reg = 0;
-
-       amo_dest.dma_amo_sys_addr = amoHostDest;
-       amo_dest.dma_amo_mod_type = amoModType;
-       MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
-       intr_dest.address = intrHostDest;
-       intr_dest.int_vector = intrVector;
-       MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg);
-
-       step.alg_step_cnt = algoStepCount;
-       MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg);
-}
-
-static inline int mbcs_getdma_start(struct mbcs_soft *soft)
-{
-       void *mmr_base;
-       struct getdma *gdma;
-       uint64_t numPkts;
-       union cm_control cm_control;
-
-       mmr_base = soft->mmr_base;
-       gdma = &soft->getdma;
-
-       /* check that host address got setup */
-       if (!gdma->hostAddr)
-               return -1;
-
-       numPkts =
-           (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
-
-       /* program engine */
-       mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr),
-                  gdma->localAddr,
-                  (gdma->localAddr < MB2) ? 0 :
-                  (gdma->localAddr < MB4) ? 1 :
-                  (gdma->localAddr < MB6) ? 2 : 3,
-                  numPkts,
-                  gdma->DoneAmoEnable,
-                  gdma->DoneIntEnable,
-                  gdma->peerIO,
-                  gdma->amoHostDest,
-                  gdma->amoModType,
-                  gdma->intrHostDest, gdma->intrVector);
-
-       /* start engine */
-       cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-       cm_control.rd_dma_go = 1;
-       MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
-       return 0;
-
-}
-
-static inline int mbcs_putdma_start(struct mbcs_soft *soft)
-{
-       void *mmr_base;
-       struct putdma *pdma;
-       uint64_t numPkts;
-       union cm_control cm_control;
-
-       mmr_base = soft->mmr_base;
-       pdma = &soft->putdma;
-
-       /* check that host address got setup */
-       if (!pdma->hostAddr)
-               return -1;
-
-       numPkts =
-           (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
-
-       /* program engine */
-       mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr),
-                  pdma->localAddr,
-                  (pdma->localAddr < MB2) ? 0 :
-                  (pdma->localAddr < MB4) ? 1 :
-                  (pdma->localAddr < MB6) ? 2 : 3,
-                  numPkts,
-                  pdma->DoneAmoEnable,
-                  pdma->DoneIntEnable,
-                  pdma->peerIO,
-                  pdma->amoHostDest,
-                  pdma->amoModType,
-                  pdma->intrHostDest, pdma->intrVector);
-
-       /* start engine */
-       cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-       cm_control.wr_dma_go = 1;
-       MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
-       return 0;
-
-}
-
-static inline int mbcs_algo_start(struct mbcs_soft *soft)
-{
-       struct algoblock *algo_soft = &soft->algo;
-       void *mmr_base = soft->mmr_base;
-       union cm_control cm_control;
-
-       if (mutex_lock_interruptible(&soft->algolock))
-               return -ERESTARTSYS;
-
-       atomic_set(&soft->algo_done, 0);
-
-       mbcs_algo_set(mmr_base,
-                algo_soft->amoHostDest,
-                algo_soft->amoModType,
-                algo_soft->intrHostDest,
-                algo_soft->intrVector, algo_soft->algoStepCount);
-
-       /* start algorithm */
-       cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-       cm_control.alg_done_int_en = 1;
-       cm_control.alg_go = 1;
-       MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
-       mutex_unlock(&soft->algolock);
-
-       return 0;
-}
-
-static inline ssize_t
-do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
-                     size_t len, loff_t * off)
-{
-       int rv = 0;
-
-       if (mutex_lock_interruptible(&soft->dmawritelock))
-               return -ERESTARTSYS;
-
-       atomic_set(&soft->dmawrite_done, 0);
-
-       soft->putdma.hostAddr = hostAddr;
-       soft->putdma.localAddr = *off;
-       soft->putdma.bytes = len;
-
-       if (mbcs_putdma_start(soft) < 0) {
-               DBG(KERN_ALERT "do_mbcs_sram_dmawrite: "
-                                       "mbcs_putdma_start failed\n");
-               rv = -EAGAIN;
-               goto dmawrite_exit;
-       }
-
-       if (wait_event_interruptible(soft->dmawrite_queue,
-                                       atomic_read(&soft->dmawrite_done))) {
-               rv = -ERESTARTSYS;
-               goto dmawrite_exit;
-       }
-
-       rv = len;
-       *off += len;
-
-dmawrite_exit:
-       mutex_unlock(&soft->dmawritelock);
-
-       return rv;
-}
-
-static inline ssize_t
-do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
-                    size_t len, loff_t * off)
-{
-       int rv = 0;
-
-       if (mutex_lock_interruptible(&soft->dmareadlock))
-               return -ERESTARTSYS;
-
-       atomic_set(&soft->dmawrite_done, 0);
-
-       soft->getdma.hostAddr = hostAddr;
-       soft->getdma.localAddr = *off;
-       soft->getdma.bytes = len;
-
-       if (mbcs_getdma_start(soft) < 0) {
-               DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n");
-               rv = -EAGAIN;
-               goto dmaread_exit;
-       }
-
-       if (wait_event_interruptible(soft->dmaread_queue,
-                                       atomic_read(&soft->dmaread_done))) {
-               rv = -ERESTARTSYS;
-               goto dmaread_exit;
-       }
-
-       rv = len;
-       *off += len;
-
-dmaread_exit:
-       mutex_unlock(&soft->dmareadlock);
-
-       return rv;
-}
-
-static int mbcs_open(struct inode *ip, struct file *fp)
-{
-       struct mbcs_soft *soft;
-       int minor;
-
-       mutex_lock(&mbcs_mutex);
-       minor = iminor(ip);
-
-       /* Nothing protects access to this list... */
-       list_for_each_entry(soft, &soft_list, list) {
-               if (soft->nasid == minor) {
-                       fp->private_data = soft->cxdev;
-                       mutex_unlock(&mbcs_mutex);
-                       return 0;
-               }
-       }
-
-       mutex_unlock(&mbcs_mutex);
-       return -ENODEV;
-}
-
-static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
-{
-       struct cx_dev *cx_dev = fp->private_data;
-       struct mbcs_soft *soft = cx_dev->soft;
-       uint64_t hostAddr;
-       int rv = 0;
-
-       hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
-       if (hostAddr == 0)
-               return -ENOMEM;
-
-       rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off);
-       if (rv < 0)
-               goto exit;
-
-       if (copy_to_user(buf, (void *)hostAddr, len))
-               rv = -EFAULT;
-
-      exit:
-       free_pages(hostAddr, get_order(len));
-
-       return rv;
-}
-
-static ssize_t
-mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
-{
-       struct cx_dev *cx_dev = fp->private_data;
-       struct mbcs_soft *soft = cx_dev->soft;
-       uint64_t hostAddr;
-       int rv = 0;
-
-       hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
-       if (hostAddr == 0)
-               return -ENOMEM;
-
-       if (copy_from_user((void *)hostAddr, buf, len)) {
-               rv = -EFAULT;
-               goto exit;
-       }
-
-       rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off);
-
-      exit:
-       free_pages(hostAddr, get_order(len));
-
-       return rv;
-}
-
-static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
-{
-       return generic_file_llseek_size(filp, off, whence, MAX_LFS_FILESIZE,
-                                       MBCS_SRAM_SIZE);
-}
-
-static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset)
-{
-       uint64_t mmr_base;
-
-       mmr_base = (uint64_t) (soft->mmr_base + offset);
-
-       return mmr_base;
-}
-
-static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft)
-{
-       soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START);
-}
-
-static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
-{
-       soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
-}
-
-static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
-{
-       struct cx_dev *cx_dev = fp->private_data;
-       struct mbcs_soft *soft = cx_dev->soft;
-
-       if (vma->vm_pgoff != 0)
-               return -EINVAL;
-
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-       /* Remap-pfn-range will mark the range VM_IO */
-       if (remap_pfn_range(vma,
-                           vma->vm_start,
-                           __pa(soft->gscr_addr) >> PAGE_SHIFT,
-                           PAGE_SIZE,
-                           vma->vm_page_prot))
-               return -EAGAIN;
-
-       return 0;
-}
-
-/**
- * mbcs_completion_intr_handler - Primary completion handler.
- * @irq: irq
- * @arg: soft struct for device
- *
- */
-static irqreturn_t
-mbcs_completion_intr_handler(int irq, void *arg)
-{
-       struct mbcs_soft *soft = (struct mbcs_soft *)arg;
-       void *mmr_base;
-       union cm_status cm_status;
-       union cm_control cm_control;
-
-       mmr_base = soft->mmr_base;
-       cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS);
-
-       if (cm_status.rd_dma_done) {
-               /* stop dma-read engine, clear status */
-               cm_control.cm_control_reg =
-                   MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-               cm_control.rd_dma_clr = 1;
-               MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
-                            cm_control.cm_control_reg);
-               atomic_set(&soft->dmaread_done, 1);
-               wake_up(&soft->dmaread_queue);
-       }
-       if (cm_status.wr_dma_done) {
-               /* stop dma-write engine, clear status */
-               cm_control.cm_control_reg =
-                   MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-               cm_control.wr_dma_clr = 1;
-               MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
-                            cm_control.cm_control_reg);
-               atomic_set(&soft->dmawrite_done, 1);
-               wake_up(&soft->dmawrite_queue);
-       }
-       if (cm_status.alg_done) {
-               /* clear status */
-               cm_control.cm_control_reg =
-                   MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-               cm_control.alg_done_clr = 1;
-               MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
-                            cm_control.cm_control_reg);
-               atomic_set(&soft->algo_done, 1);
-               wake_up(&soft->algo_queue);
-       }
-
-       return IRQ_HANDLED;
-}
-
-/**
- * mbcs_intr_alloc - Allocate interrupts.
- * @dev: device pointer
- *
- */
-static int mbcs_intr_alloc(struct cx_dev *dev)
-{
-       struct sn_irq_info *sn_irq;
-       struct mbcs_soft *soft;
-       struct getdma *getdma;
-       struct putdma *putdma;
-       struct algoblock *algo;
-
-       soft = dev->soft;
-       getdma = &soft->getdma;
-       putdma = &soft->putdma;
-       algo = &soft->algo;
-
-       soft->get_sn_irq = NULL;
-       soft->put_sn_irq = NULL;
-       soft->algo_sn_irq = NULL;
-
-       sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
-       if (sn_irq == NULL)
-               return -EAGAIN;
-       soft->get_sn_irq = sn_irq;
-       getdma->intrHostDest = sn_irq->irq_xtalkaddr;
-       getdma->intrVector = sn_irq->irq_irq;
-       if (request_irq(sn_irq->irq_irq,
-                       (void *)mbcs_completion_intr_handler, IRQF_SHARED,
-                       "MBCS get intr", (void *)soft)) {
-               tiocx_irq_free(soft->get_sn_irq);
-               return -EAGAIN;
-       }
-
-       sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
-       if (sn_irq == NULL) {
-               free_irq(soft->get_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->get_sn_irq);
-               return -EAGAIN;
-       }
-       soft->put_sn_irq = sn_irq;
-       putdma->intrHostDest = sn_irq->irq_xtalkaddr;
-       putdma->intrVector = sn_irq->irq_irq;
-       if (request_irq(sn_irq->irq_irq,
-                       (void *)mbcs_completion_intr_handler, IRQF_SHARED,
-                       "MBCS put intr", (void *)soft)) {
-               tiocx_irq_free(soft->put_sn_irq);
-               free_irq(soft->get_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->get_sn_irq);
-               return -EAGAIN;
-       }
-
-       sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
-       if (sn_irq == NULL) {
-               free_irq(soft->put_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->put_sn_irq);
-               free_irq(soft->get_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->get_sn_irq);
-               return -EAGAIN;
-       }
-       soft->algo_sn_irq = sn_irq;
-       algo->intrHostDest = sn_irq->irq_xtalkaddr;
-       algo->intrVector = sn_irq->irq_irq;
-       if (request_irq(sn_irq->irq_irq,
-                       (void *)mbcs_completion_intr_handler, IRQF_SHARED,
-                       "MBCS algo intr", (void *)soft)) {
-               tiocx_irq_free(soft->algo_sn_irq);
-               free_irq(soft->put_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->put_sn_irq);
-               free_irq(soft->get_sn_irq->irq_irq, soft);
-               tiocx_irq_free(soft->get_sn_irq);
-               return -EAGAIN;
-       }
-
-       return 0;
-}
-
-/**
- * mbcs_intr_dealloc - Remove interrupts.
- * @dev: device pointer
- *
- */
-static void mbcs_intr_dealloc(struct cx_dev *dev)
-{
-       struct mbcs_soft *soft;
-
-       soft = dev->soft;
-
-       free_irq(soft->get_sn_irq->irq_irq, soft);
-       tiocx_irq_free(soft->get_sn_irq);
-       free_irq(soft->put_sn_irq->irq_irq, soft);
-       tiocx_irq_free(soft->put_sn_irq);
-       free_irq(soft->algo_sn_irq->irq_irq, soft);
-       tiocx_irq_free(soft->algo_sn_irq);
-}
-
-static inline int mbcs_hw_init(struct mbcs_soft *soft)
-{
-       void *mmr_base = soft->mmr_base;
-       union cm_control cm_control;
-       union cm_req_timeout cm_req_timeout;
-       uint64_t err_stat;
-
-       cm_req_timeout.cm_req_timeout_reg =
-           MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT);
-
-       cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK;
-       MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT,
-                    cm_req_timeout.cm_req_timeout_reg);
-
-       mbcs_gscr_pioaddr_set(soft);
-       mbcs_debug_pioaddr_set(soft);
-
-       /* clear errors */
-       err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT);
-       MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat);
-       MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1);
-
-       /* enable interrupts */
-       /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */
-       MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL);
-
-       /* arm status regs and clear engines */
-       cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
-       cm_control.rearm_stat_regs = 1;
-       cm_control.alg_clr = 1;
-       cm_control.wr_dma_clr = 1;
-       cm_control.rd_dma_clr = 1;
-
-       MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
-       return 0;
-}
-
-static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       struct mbcs_soft *soft = cx_dev->soft;
-       uint64_t debug0;
-
-       /*
-        * By convention, the first debug register contains the
-        * algorithm number and revision.
-        */
-       debug0 = *(uint64_t *) soft->debug_addr;
-
-       return sprintf(buf, "0x%x 0x%x\n",
-                      upper_32_bits(debug0), lower_32_bits(debug0));
-}
-
-static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       int n;
-       struct cx_dev *cx_dev = to_cx_dev(dev);
-       struct mbcs_soft *soft = cx_dev->soft;
-
-       if (count <= 0)
-               return 0;
-
-       n = simple_strtoul(buf, NULL, 0);
-
-       if (n == 1) {
-               mbcs_algo_start(soft);
-               if (wait_event_interruptible(soft->algo_queue,
-                                       atomic_read(&soft->algo_done)))
-                       return -ERESTARTSYS;
-       }
-
-       return count;
-}
-
-DEVICE_ATTR(algo, 0644, show_algo, store_algo);
-
-/**
- * mbcs_probe - Initialize for device
- * @dev: device pointer
- * @device_id: id table pointer
- *
- */
-static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
-{
-       struct mbcs_soft *soft;
-
-       dev->soft = NULL;
-
-       soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
-       if (soft == NULL)
-               return -ENOMEM;
-
-       soft->nasid = dev->cx_id.nasid;
-       list_add(&soft->list, &soft_list);
-       soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid);
-       dev->soft = soft;
-       soft->cxdev = dev;
-
-       init_waitqueue_head(&soft->dmawrite_queue);
-       init_waitqueue_head(&soft->dmaread_queue);
-       init_waitqueue_head(&soft->algo_queue);
-
-       mutex_init(&soft->dmawritelock);
-       mutex_init(&soft->dmareadlock);
-       mutex_init(&soft->algolock);
-
-       mbcs_getdma_init(&soft->getdma);
-       mbcs_putdma_init(&soft->putdma);
-       mbcs_algo_init(&soft->algo);
-
-       mbcs_hw_init(soft);
-
-       /* Allocate interrupts */
-       mbcs_intr_alloc(dev);
-
-       device_create_file(&dev->dev, &dev_attr_algo);
-
-       return 0;
-}
-
-static int mbcs_remove(struct cx_dev *dev)
-{
-       if (dev->soft) {
-               mbcs_intr_dealloc(dev);
-               kfree(dev->soft);
-       }
-
-       device_remove_file(&dev->dev, &dev_attr_algo);
-
-       return 0;
-}
-
-static const struct cx_device_id mbcs_id_table[] = {
-       {
-        .part_num = MBCS_PART_NUM,
-        .mfg_num = MBCS_MFG_NUM,
-        },
-       {
-        .part_num = MBCS_PART_NUM_ALG0,
-        .mfg_num = MBCS_MFG_NUM,
-        },
-       {0, 0}
-};
-
-MODULE_DEVICE_TABLE(cx, mbcs_id_table);
-
-static struct cx_drv mbcs_driver = {
-       .name = DEVICE_NAME,
-       .id_table = mbcs_id_table,
-       .probe = mbcs_probe,
-       .remove = mbcs_remove,
-};
-
-static void __exit mbcs_exit(void)
-{
-       unregister_chrdev(mbcs_major, DEVICE_NAME);
-       cx_driver_unregister(&mbcs_driver);
-}
-
-static int __init mbcs_init(void)
-{
-       int rv;
-
-       if (!ia64_platform_is("sn2"))
-               return -ENODEV;
-
-       // Put driver into chrdevs[].  Get major number.
-       rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops);
-       if (rv < 0) {
-               DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv);
-               return rv;
-       }
-       mbcs_major = rv;
-
-       return cx_driver_register(&mbcs_driver);
-}
-
-module_init(mbcs_init);
-module_exit(mbcs_exit);
-
-MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
-MODULE_DESCRIPTION("Driver for MOATB Core Services");
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
deleted file mode 100644 (file)
index 1a36884..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
- */
-
-#ifndef __MBCS_H__
-#define __MBCS_H__
-
-/*
- * General macros
- */
-#define MB     (1024*1024)
-#define MB2    (2*MB)
-#define MB4    (4*MB)
-#define MB6    (6*MB)
-
-/*
- * Offsets and masks
- */
-#define MBCS_CM_ID             0x0000  /* Identification */
-#define MBCS_CM_STATUS         0x0008  /* Status */
-#define MBCS_CM_ERROR_DETAIL1  0x0010  /* Error Detail1 */
-#define MBCS_CM_ERROR_DETAIL2  0x0018  /* Error Detail2 */
-#define MBCS_CM_CONTROL                0x0020  /* Control */
-#define MBCS_CM_REQ_TOUT       0x0028  /* Request Time-out */
-#define MBCS_CM_ERR_INT_DEST   0x0038  /* Error Interrupt Destination */
-#define MBCS_CM_TARG_FL                0x0050  /* Target Flush */
-#define MBCS_CM_ERR_STAT       0x0060  /* Error Status */
-#define MBCS_CM_CLR_ERR_STAT   0x0068  /* Clear Error Status */
-#define MBCS_CM_ERR_INT_EN     0x0070  /* Error Interrupt Enable */
-#define MBCS_RD_DMA_SYS_ADDR   0x0100  /* Read DMA System Address */
-#define MBCS_RD_DMA_LOC_ADDR   0x0108  /* Read DMA Local Address */
-#define MBCS_RD_DMA_CTRL       0x0110  /* Read DMA Control */
-#define MBCS_RD_DMA_AMO_DEST   0x0118  /* Read DMA AMO Destination */
-#define MBCS_RD_DMA_INT_DEST   0x0120  /* Read DMA Interrupt Destination */
-#define MBCS_RD_DMA_AUX_STAT   0x0130  /* Read DMA Auxiliary Status */
-#define MBCS_WR_DMA_SYS_ADDR   0x0200  /* Write DMA System Address */
-#define MBCS_WR_DMA_LOC_ADDR   0x0208  /* Write DMA Local Address */
-#define MBCS_WR_DMA_CTRL       0x0210  /* Write DMA Control */
-#define MBCS_WR_DMA_AMO_DEST   0x0218  /* Write DMA AMO Destination */
-#define MBCS_WR_DMA_INT_DEST   0x0220  /* Write DMA Interrupt Destination */
-#define MBCS_WR_DMA_AUX_STAT   0x0230  /* Write DMA Auxiliary Status */
-#define MBCS_ALG_AMO_DEST      0x0300  /* Algorithm AMO Destination */
-#define MBCS_ALG_INT_DEST      0x0308  /* Algorithm Interrupt Destination */
-#define MBCS_ALG_OFFSETS       0x0310
-#define MBCS_ALG_STEP          0x0318  /* Algorithm Step */
-
-#define MBCS_GSCR_START                0x0000000
-#define MBCS_DEBUG_START       0x0100000
-#define MBCS_RAM0_START                0x0200000
-#define MBCS_RAM1_START                0x0400000
-#define MBCS_RAM2_START                0x0600000
-
-#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL
-//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL
-
-#define MBCS_SRAM_SIZE         (1024*1024)
-#define MBCS_CACHELINE_SIZE    128
-
-/*
- * MMR get's and put's
- */
-#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset))
-#define MBCS_MMR_SET(mmr_base, offset, value) {                        \
-       uint64_t *mbcs_mmr_set_u64p, readback;                          \
-       mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset);    \
-       *mbcs_mmr_set_u64p = value;                                     \
-       readback = *mbcs_mmr_set_u64p; \
-}
-#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset)
-#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0)
-
-/*
- * MBCS mmr structures
- */
-union cm_id {
-       uint64_t cm_id_reg;
-       struct {
-               uint64_t always_one:1,  // 0
-                mfg_id:11,     // 11:1
-                part_num:16,   // 27:12
-                bitstream_rev:8,       // 35:28
-               :28;            // 63:36
-       };
-};
-
-union cm_status {
-       uint64_t cm_status_reg;
-       struct {
-               uint64_t pending_reads:8,       // 7:0
-                pending_writes:8,      // 15:8
-                ice_rsp_credits:8,     // 23:16
-                ice_req_credits:8,     // 31:24
-                cm_req_credits:8,      // 39:32
-               :1,             // 40
-                rd_dma_in_progress:1,  // 41
-                rd_dma_done:1, // 42
-               :1,             // 43
-                wr_dma_in_progress:1,  // 44
-                wr_dma_done:1, // 45
-                alg_waiting:1, // 46
-                alg_pipe_running:1,    // 47
-                alg_done:1,    // 48
-               :3,             // 51:49
-                pending_int_reqs:8,    // 59:52
-               :3,             // 62:60
-                alg_half_speed_sel:1;  // 63
-       };
-};
-
-union cm_error_detail1 {
-       uint64_t cm_error_detail1_reg;
-       struct {
-               uint64_t packet_type:4, // 3:0
-                source_id:2,   // 5:4
-                data_size:2,   // 7:6
-                tnum:8,        // 15:8
-                byte_enable:8, // 23:16
-                gfx_cred:8,    // 31:24
-                read_type:2,   // 33:32
-                pio_or_memory:1,       // 34
-                head_cw_error:1,       // 35
-               :12,            // 47:36
-                head_error_bit:1,      // 48
-                data_error_bit:1,      // 49
-               :13,            // 62:50
-                valid:1;       // 63
-       };
-};
-
-union cm_error_detail2 {
-       uint64_t cm_error_detail2_reg;
-       struct {
-               uint64_t address:56,    // 55:0
-               :8;             // 63:56
-       };
-};
-
-union cm_control {
-       uint64_t cm_control_reg;
-       struct {
-               uint64_t cm_id:2,       // 1:0
-               :2,             // 3:2
-                max_trans:5,   // 8:4
-               :3,             // 11:9
-                address_mode:1,        // 12
-               :7,             // 19:13
-                credit_limit:8,        // 27:20
-               :5,             // 32:28
-                rearm_stat_regs:1,     // 33
-                prescalar_byp:1,       // 34
-                force_gap_war:1,       // 35
-                rd_dma_go:1,   // 36
-                wr_dma_go:1,   // 37
-                alg_go:1,      // 38
-                rd_dma_clr:1,  // 39
-                wr_dma_clr:1,  // 40
-                alg_clr:1,     // 41
-               :2,             // 43:42
-                alg_wait_step:1,       // 44
-                alg_done_amo_en:1,     // 45
-                alg_done_int_en:1,     // 46
-               :1,             // 47
-                alg_sram0_locked:1,    // 48
-                alg_sram1_locked:1,    // 49
-                alg_sram2_locked:1,    // 50
-                alg_done_clr:1,        // 51
-               :12;            // 63:52
-       };
-};
-
-union cm_req_timeout {
-       uint64_t cm_req_timeout_reg;
-       struct {
-               uint64_t time_out:24,   // 23:0
-               :40;            // 63:24
-       };
-};
-
-union intr_dest {
-       uint64_t intr_dest_reg;
-       struct {
-               uint64_t address:56,    // 55:0
-                int_vector:8;  // 63:56
-       };
-};
-
-union cm_error_status {
-       uint64_t cm_error_status_reg;
-       struct {
-               uint64_t ecc_sbe:1,     // 0
-                ecc_mbe:1,     // 1
-                unsupported_req:1,     // 2
-                unexpected_rsp:1,      // 3
-                bad_length:1,  // 4
-                bad_datavalid:1,       // 5
-                buffer_overflow:1,     // 6
-                request_timeout:1,     // 7
-               :8,             // 15:8
-                head_inv_data_size:1,  // 16
-                rsp_pactype_inv:1,     // 17
-                head_sb_err:1, // 18
-                missing_head:1,        // 19
-                head_inv_rd_type:1,    // 20
-                head_cmd_err_bit:1,    // 21
-                req_addr_align_inv:1,  // 22
-                pio_req_addr_inv:1,    // 23
-                req_range_dsize_inv:1, // 24
-                early_term:1,  // 25
-                early_tail:1,  // 26
-                missing_tail:1,        // 27
-                data_flit_sb_err:1,    // 28
-                cm2hcm_req_cred_of:1,  // 29
-                cm2hcm_rsp_cred_of:1,  // 30
-                rx_bad_didn:1, // 31
-                rd_dma_err_rsp:1,      // 32
-                rd_dma_tnum_tout:1,    // 33
-                rd_dma_multi_tnum_tou:1,       // 34
-                wr_dma_err_rsp:1,      // 35
-                wr_dma_tnum_tout:1,    // 36
-                wr_dma_multi_tnum_tou:1,       // 37
-                alg_data_overflow:1,   // 38
-                alg_data_underflow:1,  // 39
-                ram0_access_conflict:1,        // 40
-                ram1_access_conflict:1,        // 41
-                ram2_access_conflict:1,        // 42
-                ram0_perr:1,   // 43
-                ram1_perr:1,   // 44
-                ram2_perr:1,   // 45
-                int_gen_rsp_err:1,     // 46
-                int_gen_tnum_tout:1,   // 47
-                rd_dma_prog_err:1,     // 48
-                wr_dma_prog_err:1,     // 49
-               :14;            // 63:50
-       };
-};
-
-union cm_clr_error_status {
-       uint64_t cm_clr_error_status_reg;
-       struct {
-               uint64_t clr_ecc_sbe:1, // 0
-                clr_ecc_mbe:1, // 1
-                clr_unsupported_req:1, // 2
-                clr_unexpected_rsp:1,  // 3
-                clr_bad_length:1,      // 4
-                clr_bad_datavalid:1,   // 5
-                clr_buffer_overflow:1, // 6
-                clr_request_timeout:1, // 7
-               :8,             // 15:8
-                clr_head_inv_data_siz:1,       // 16
-                clr_rsp_pactype_inv:1, // 17
-                clr_head_sb_err:1,     // 18
-                clr_missing_head:1,    // 19
-                clr_head_inv_rd_type:1,        // 20
-                clr_head_cmd_err_bit:1,        // 21
-                clr_req_addr_align_in:1,       // 22
-                clr_pio_req_addr_inv:1,        // 23
-                clr_req_range_dsize_i:1,       // 24
-                clr_early_term:1,      // 25
-                clr_early_tail:1,      // 26
-                clr_missing_tail:1,    // 27
-                clr_data_flit_sb_err:1,        // 28
-                clr_cm2hcm_req_cred_o:1,       // 29
-                clr_cm2hcm_rsp_cred_o:1,       // 30
-                clr_rx_bad_didn:1,     // 31
-                clr_rd_dma_err_rsp:1,  // 32
-                clr_rd_dma_tnum_tout:1,        // 33
-                clr_rd_dma_multi_tnum:1,       // 34
-                clr_wr_dma_err_rsp:1,  // 35
-                clr_wr_dma_tnum_tout:1,        // 36
-                clr_wr_dma_multi_tnum:1,       // 37
-                clr_alg_data_overflow:1,       // 38
-                clr_alg_data_underflo:1,       // 39
-                clr_ram0_access_confl:1,       // 40
-                clr_ram1_access_confl:1,       // 41
-                clr_ram2_access_confl:1,       // 42
-                clr_ram0_perr:1,       // 43
-                clr_ram1_perr:1,       // 44
-                clr_ram2_perr:1,       // 45
-                clr_int_gen_rsp_err:1, // 46
-                clr_int_gen_tnum_tout:1,       // 47
-                clr_rd_dma_prog_err:1, // 48
-                clr_wr_dma_prog_err:1, // 49
-               :14;            // 63:50
-       };
-};
-
-union cm_error_intr_enable {
-       uint64_t cm_error_intr_enable_reg;
-       struct {
-               uint64_t int_en_ecc_sbe:1,      // 0
-                int_en_ecc_mbe:1,      // 1
-                int_en_unsupported_re:1,       // 2
-                int_en_unexpected_rsp:1,       // 3
-                int_en_bad_length:1,   // 4
-                int_en_bad_datavalid:1,        // 5
-                int_en_buffer_overflo:1,       // 6
-                int_en_request_timeou:1,       // 7
-               :8,             // 15:8
-                int_en_head_inv_data_:1,       // 16
-                int_en_rsp_pactype_in:1,       // 17
-                int_en_head_sb_err:1,  // 18
-                int_en_missing_head:1, // 19
-                int_en_head_inv_rd_ty:1,       // 20
-                int_en_head_cmd_err_b:1,       // 21
-                int_en_req_addr_align:1,       // 22
-                int_en_pio_req_addr_i:1,       // 23
-                int_en_req_range_dsiz:1,       // 24
-                int_en_early_term:1,   // 25
-                int_en_early_tail:1,   // 26
-                int_en_missing_tail:1, // 27
-                int_en_data_flit_sb_e:1,       // 28
-                int_en_cm2hcm_req_cre:1,       // 29
-                int_en_cm2hcm_rsp_cre:1,       // 30
-                int_en_rx_bad_didn:1,  // 31
-                int_en_rd_dma_err_rsp:1,       // 32
-                int_en_rd_dma_tnum_to:1,       // 33
-                int_en_rd_dma_multi_t:1,       // 34
-                int_en_wr_dma_err_rsp:1,       // 35
-                int_en_wr_dma_tnum_to:1,       // 36
-                int_en_wr_dma_multi_t:1,       // 37
-                int_en_alg_data_overf:1,       // 38
-                int_en_alg_data_under:1,       // 39
-                int_en_ram0_access_co:1,       // 40
-                int_en_ram1_access_co:1,       // 41
-                int_en_ram2_access_co:1,       // 42
-                int_en_ram0_perr:1,    // 43
-                int_en_ram1_perr:1,    // 44
-                int_en_ram2_perr:1,    // 45
-                int_en_int_gen_rsp_er:1,       // 46
-                int_en_int_gen_tnum_t:1,       // 47
-                int_en_rd_dma_prog_er:1,       // 48
-                int_en_wr_dma_prog_er:1,       // 49
-               :14;            // 63:50
-       };
-};
-
-struct cm_mmr {
-       union cm_id id;
-       union cm_status status;
-       union cm_error_detail1 err_detail1;
-       union cm_error_detail2 err_detail2;
-       union cm_control control;
-       union cm_req_timeout req_timeout;
-       uint64_t reserved1[1];
-       union intr_dest int_dest;
-       uint64_t reserved2[2];
-       uint64_t targ_flush;
-       uint64_t reserved3[1];
-       union cm_error_status err_status;
-       union cm_clr_error_status clr_err_status;
-       union cm_error_intr_enable int_enable;
-};
-
-union dma_hostaddr {
-       uint64_t dma_hostaddr_reg;
-       struct {
-               uint64_t dma_sys_addr:56,       // 55:0
-               :8;             // 63:56
-       };
-};
-
-union dma_localaddr {
-       uint64_t dma_localaddr_reg;
-       struct {
-               uint64_t dma_ram_addr:21,       // 20:0
-                dma_ram_sel:2, // 22:21
-               :41;            // 63:23
-       };
-};
-
-union dma_control {
-       uint64_t dma_control_reg;
-       struct {
-               uint64_t dma_op_length:16,      // 15:0
-               :18,            // 33:16
-                done_amo_en:1, // 34
-                done_int_en:1, // 35
-               :1,             // 36
-                pio_mem_n:1,   // 37
-               :26;            // 63:38
-       };
-};
-
-union dma_amo_dest {
-       uint64_t dma_amo_dest_reg;
-       struct {
-               uint64_t dma_amo_sys_addr:56,   // 55:0
-                dma_amo_mod_type:3,    // 58:56
-               :5;             // 63:59
-       };
-};
-
-union rdma_aux_status {
-       uint64_t rdma_aux_status_reg;
-       struct {
-               uint64_t op_num_pacs_left:17,   // 16:0
-               :5,             // 21:17
-                lrsp_buff_empty:1,     // 22
-               :17,            // 39:23
-                pending_reqs_left:6,   // 45:40
-               :18;            // 63:46
-       };
-};
-
-struct rdma_mmr {
-       union dma_hostaddr host_addr;
-       union dma_localaddr local_addr;
-       union dma_control control;
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union rdma_aux_status aux_status;
-};
-
-union wdma_aux_status {
-       uint64_t wdma_aux_status_reg;
-       struct {
-               uint64_t op_num_pacs_left:17,   // 16:0
-               :4,             // 20:17
-                lreq_buff_empty:1,     // 21
-               :18,            // 39:22
-                pending_reqs_left:6,   // 45:40
-               :18;            // 63:46
-       };
-};
-
-struct wdma_mmr {
-       union dma_hostaddr host_addr;
-       union dma_localaddr local_addr;
-       union dma_control control;
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union wdma_aux_status aux_status;
-};
-
-union algo_step {
-       uint64_t algo_step_reg;
-       struct {
-               uint64_t alg_step_cnt:16,       // 15:0
-               :48;            // 63:16
-       };
-};
-
-struct algo_mmr {
-       union dma_amo_dest amo_dest;
-       union intr_dest intr_dest;
-       union {
-               uint64_t algo_offset_reg;
-               struct {
-                       uint64_t sram0_offset:7,        // 6:0
-                       reserved0:1,    // 7
-                       sram1_offset:7, // 14:8
-                       reserved1:1,    // 15
-                       sram2_offset:7, // 22:16
-                       reserved2:14;   // 63:23
-               };
-       } sram_offset;
-       union algo_step step;
-};
-
-struct mbcs_mmr {
-       struct cm_mmr cm;
-       uint64_t reserved1[17];
-       struct rdma_mmr rdDma;
-       uint64_t reserved2[25];
-       struct wdma_mmr wrDma;
-       uint64_t reserved3[25];
-       struct algo_mmr algo;
-       uint64_t reserved4[156];
-};
-
-/*
- * defines
- */
-#define DEVICE_NAME "mbcs"
-#define MBCS_PART_NUM 0xfff0
-#define MBCS_PART_NUM_ALG0 0xf001
-#define MBCS_MFG_NUM  0x1
-
-struct algoblock {
-       uint64_t amoHostDest;
-       uint64_t amoModType;
-       uint64_t intrHostDest;
-       uint64_t intrVector;
-       uint64_t algoStepCount;
-};
-
-struct getdma {
-       uint64_t hostAddr;
-       uint64_t localAddr;
-       uint64_t bytes;
-       uint64_t DoneAmoEnable;
-       uint64_t DoneIntEnable;
-       uint64_t peerIO;
-       uint64_t amoHostDest;
-       uint64_t amoModType;
-       uint64_t intrHostDest;
-       uint64_t intrVector;
-};
-
-struct putdma {
-       uint64_t hostAddr;
-       uint64_t localAddr;
-       uint64_t bytes;
-       uint64_t DoneAmoEnable;
-       uint64_t DoneIntEnable;
-       uint64_t peerIO;
-       uint64_t amoHostDest;
-       uint64_t amoModType;
-       uint64_t intrHostDest;
-       uint64_t intrVector;
-};
-
-struct mbcs_soft {
-       struct list_head list;
-       struct cx_dev *cxdev;
-       int major;
-       int nasid;
-       void *mmr_base;
-       wait_queue_head_t dmawrite_queue;
-       wait_queue_head_t dmaread_queue;
-       wait_queue_head_t algo_queue;
-       struct sn_irq_info *get_sn_irq;
-       struct sn_irq_info *put_sn_irq;
-       struct sn_irq_info *algo_sn_irq;
-       struct getdma getdma;
-       struct putdma putdma;
-       struct algoblock algo;
-       uint64_t gscr_addr;     // pio addr
-       uint64_t ram0_addr;     // pio addr
-       uint64_t ram1_addr;     // pio addr
-       uint64_t ram2_addr;     // pio addr
-       uint64_t debug_addr;    // pio addr
-       atomic_t dmawrite_done;
-       atomic_t dmaread_done;
-       atomic_t algo_done;
-       struct mutex dmawritelock;
-       struct mutex dmareadlock;
-       struct mutex algolock;
-};
-
-static int mbcs_open(struct inode *ip, struct file *fp);
-static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
-                             loff_t * off);
-static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
-                              loff_t * off);
-static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
-
-#endif                         // __MBCS_H__
index e75c9df..a9d9f07 100644 (file)
@@ -9,11 +9,8 @@
  *
  * This driver exports the SN special memory (mspec) facility to user
  * processes.
- * There are three types of memory made available thru this driver:
- * fetchops, uncached and cached.
- *
- * Fetchops are atomic memory operations that are implemented in the
- * memory controller on SGI SN hardware.
+ * There are two types of memory made available thru this driver:
+ * uncached and cached.
  *
  * Uncached are used for memory write combining feature of the ia64
  * cpu.
 #include <linux/atomic.h>
 #include <asm/tlbflush.h>
 #include <asm/uncached.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/io.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/shubio.h>
 
 
-#define FETCHOP_ID     "SGI Fetchop,"
 #define CACHED_ID      "Cached,"
 #define UNCACHED_ID    "Uncached"
 #define REVISION       "4.0"
  * Page types allocated by the device.
  */
 enum mspec_page_type {
-       MSPEC_FETCHOP = 1,
-       MSPEC_CACHED,
+       MSPEC_CACHED = 2,
        MSPEC_UNCACHED
 };
 
-#ifdef CONFIG_SGI_SN
-static int is_sn2;
-#else
-#define is_sn2         0
-#endif
-
 /*
  * One of these structures is allocated when an mspec region is mmaped. The
  * structure is pointed to by the vma->vm_private_data field in the vma struct.
@@ -96,39 +78,6 @@ struct vma_data {
        unsigned long maddr[0]; /* Array of MSPEC addresses. */
 };
 
-/* used on shub2 to clear FOP cache in the HUB */
-static unsigned long scratch_page[MAX_NUMNODES];
-#define SH2_AMO_CACHE_ENTRIES  4
-
-static inline int
-mspec_zero_block(unsigned long addr, int len)
-{
-       int status;
-
-       if (is_sn2) {
-               if (is_shub2()) {
-                       int nid;
-                       void *p;
-                       int i;
-
-                       nid = nasid_to_cnodeid(get_node_number(__pa(addr)));
-                       p = (void *)TO_AMO(scratch_page[nid]);
-
-                       for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) {
-                               FETCHOP_LOAD_OP(p, FETCHOP_LOAD);
-                               p += FETCHOP_VAR_SIZE;
-                       }
-               }
-
-               status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len,
-                                 BTE_WACQUIRE | BTE_ZERO_FILL, NULL);
-       } else {
-               memset((char *) addr, 0, len);
-               status = 0;
-       }
-       return status;
-}
-
 /*
  * mspec_open
  *
@@ -173,11 +122,8 @@ mspec_close(struct vm_area_struct *vma)
                 */
                my_page = vdata->maddr[index];
                vdata->maddr[index] = 0;
-               if (!mspec_zero_block(my_page, PAGE_SIZE))
-                       uncached_free_page(my_page, 1);
-               else
-                       printk(KERN_WARNING "mspec_close(): "
-                              "failed to zero page %ld\n", my_page);
+               memset((char *)my_page, 0, PAGE_SIZE);
+               uncached_free_page(my_page, 1);
        }
 
        kvfree(vdata);
@@ -213,11 +159,7 @@ mspec_fault(struct vm_fault *vmf)
                spin_unlock(&vdata->lock);
        }
 
-       if (vdata->type == MSPEC_FETCHOP)
-               paddr = TO_AMO(maddr);
-       else
-               paddr = maddr & ~__IA64_UNCACHED_OFFSET;
-
+       paddr = maddr & ~__IA64_UNCACHED_OFFSET;
        pfn = paddr >> PAGE_SHIFT;
 
        return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
@@ -269,19 +211,13 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
        vma->vm_private_data = vdata;
 
        vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
-       if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
+       if (vdata->type == MSPEC_UNCACHED)
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        vma->vm_ops = &mspec_vm_ops;
 
        return 0;
 }
 
-static int
-fetchop_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       return mspec_mmap(file, vma, MSPEC_FETCHOP);
-}
-
 static int
 cached_mmap(struct file *file, struct vm_area_struct *vma)
 {
@@ -294,18 +230,6 @@ uncached_mmap(struct file *file, struct vm_area_struct *vma)
        return mspec_mmap(file, vma, MSPEC_UNCACHED);
 }
 
-static const struct file_operations fetchop_fops = {
-       .owner = THIS_MODULE,
-       .mmap = fetchop_mmap,
-       .llseek = noop_llseek,
-};
-
-static struct miscdevice fetchop_miscdev = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "sgi_fetchop",
-       .fops = &fetchop_fops
-};
-
 static const struct file_operations cached_fops = {
        .owner = THIS_MODULE,
        .mmap = cached_mmap,
@@ -339,89 +263,32 @@ static int __init
 mspec_init(void)
 {
        int ret;
-       int nid;
-
-       /*
-        * The fetchop device only works on SN2 hardware, uncached and cached
-        * memory drivers should both be valid on all ia64 hardware
-        */
-#ifdef CONFIG_SGI_SN
-       if (ia64_platform_is("sn2")) {
-               is_sn2 = 1;
-               if (is_shub2()) {
-                       ret = -ENOMEM;
-                       for_each_node_state(nid, N_ONLINE) {
-                               int actual_nid;
-                               int nasid;
-                               unsigned long phys;
-
-                               scratch_page[nid] = uncached_alloc_page(nid, 1);
-                               if (scratch_page[nid] == 0)
-                                       goto free_scratch_pages;
-                               phys = __pa(scratch_page[nid]);
-                               nasid = get_node_number(phys);
-                               actual_nid = nasid_to_cnodeid(nasid);
-                               if (actual_nid != nid)
-                                       goto free_scratch_pages;
-                       }
-               }
 
-               ret = misc_register(&fetchop_miscdev);
-               if (ret) {
-                       printk(KERN_ERR
-                              "%s: failed to register device %i\n",
-                              FETCHOP_ID, ret);
-                       goto free_scratch_pages;
-               }
-       }
-#endif
        ret = misc_register(&cached_miscdev);
        if (ret) {
                printk(KERN_ERR "%s: failed to register device %i\n",
                       CACHED_ID, ret);
-               if (is_sn2)
-                       misc_deregister(&fetchop_miscdev);
-               goto free_scratch_pages;
+               return ret;
        }
        ret = misc_register(&uncached_miscdev);
        if (ret) {
                printk(KERN_ERR "%s: failed to register device %i\n",
                       UNCACHED_ID, ret);
                misc_deregister(&cached_miscdev);
-               if (is_sn2)
-                       misc_deregister(&fetchop_miscdev);
-               goto free_scratch_pages;
+               return ret;
        }
 
-       printk(KERN_INFO "%s %s initialized devices: %s %s %s\n",
-              MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "",
-              CACHED_ID, UNCACHED_ID);
+       printk(KERN_INFO "%s %s initialized devices: %s %s\n",
+              MSPEC_BASENAME, REVISION, CACHED_ID, UNCACHED_ID);
 
        return 0;
-
- free_scratch_pages:
-       for_each_node(nid) {
-               if (scratch_page[nid] != 0)
-                       uncached_free_page(scratch_page[nid], 1);
-       }
-       return ret;
 }
 
 static void __exit
 mspec_exit(void)
 {
-       int nid;
-
        misc_deregister(&uncached_miscdev);
        misc_deregister(&cached_miscdev);
-       if (is_sn2) {
-               misc_deregister(&fetchop_miscdev);
-
-               for_each_node(nid) {
-                       if (scratch_page[nid] != 0)
-                               uncached_free_page(scratch_page[nid], 1);
-               }
-       }
 }
 
 module_init(mspec_init);
index 5d5ea4c..566922d 100644 (file)
@@ -2445,3 +2445,17 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
        credit_entropy_bits(poolp, entropy);
 }
 EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
+
+/* Handle random seed passed by bootloader.
+ * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise
+ * it would be regarded as device data.
+ * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER.
+ */
+void add_bootloader_randomness(const void *buf, unsigned int size)
+{
+       if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER))
+               add_hwgenerator_randomness(buf, size, size * 8);
+       else
+               add_device_randomness(buf, size);
+}
+EXPORT_SYMBOL_GPL(add_bootloader_randomness);
\ No newline at end of file
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
deleted file mode 100644 (file)
index 5918ea7..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004, 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * System controller communication driver
- *
- * This driver allows a user process to communicate with the system
- * controller (a.k.a. "IRouter") network in an SGI SN system.
- */
-
-#include <linux/interrupt.h>
-#include <linux/sched/signal.h>
-#include <linux/device.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/module.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/nodepda.h>
-#include "snsc.h"
-
-#define SYSCTL_BASENAME        "snsc"
-
-#define SCDRV_BUFSZ    2048
-#define SCDRV_TIMEOUT  1000
-
-static DEFINE_MUTEX(scdrv_mutex);
-static irqreturn_t
-scdrv_interrupt(int irq, void *subch_data)
-{
-       struct subch_data_s *sd = subch_data;
-       unsigned long flags;
-       int status;
-
-       spin_lock_irqsave(&sd->sd_rlock, flags);
-       spin_lock(&sd->sd_wlock);
-       status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
-
-       if (status > 0) {
-               if (status & SAL_IROUTER_INTR_RECV) {
-                       wake_up(&sd->sd_rq);
-               }
-               if (status & SAL_IROUTER_INTR_XMIT) {
-                       ia64_sn_irtr_intr_disable
-                           (sd->sd_nasid, sd->sd_subch,
-                            SAL_IROUTER_INTR_XMIT);
-                       wake_up(&sd->sd_wq);
-               }
-       }
-       spin_unlock(&sd->sd_wlock);
-       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-       return IRQ_HANDLED;
-}
-
-/*
- * scdrv_open
- *
- * Reserve a subchannel for system controller communication.
- */
-
-static int
-scdrv_open(struct inode *inode, struct file *file)
-{
-       struct sysctl_data_s *scd;
-       struct subch_data_s *sd;
-       int rv;
-
-       /* look up device info for this device file */
-       scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev);
-
-       /* allocate memory for subchannel data */
-       sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
-       if (sd == NULL) {
-               printk("%s: couldn't allocate subchannel data\n",
-                      __func__);
-               return -ENOMEM;
-       }
-
-       /* initialize subch_data_s fields */
-       sd->sd_nasid = scd->scd_nasid;
-       sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid);
-
-       if (sd->sd_subch < 0) {
-               kfree(sd);
-               printk("%s: couldn't allocate subchannel\n", __func__);
-               return -EBUSY;
-       }
-
-       spin_lock_init(&sd->sd_rlock);
-       spin_lock_init(&sd->sd_wlock);
-       init_waitqueue_head(&sd->sd_rq);
-       init_waitqueue_head(&sd->sd_wq);
-       sema_init(&sd->sd_rbs, 1);
-       sema_init(&sd->sd_wbs, 1);
-
-       file->private_data = sd;
-
-       /* hook this subchannel up to the system controller interrupt */
-       mutex_lock(&scdrv_mutex);
-       rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
-                        IRQF_SHARED, SYSCTL_BASENAME, sd);
-       if (rv) {
-               ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
-               kfree(sd);
-               printk("%s: irq request failed (%d)\n", __func__, rv);
-               mutex_unlock(&scdrv_mutex);
-               return -EBUSY;
-       }
-       mutex_unlock(&scdrv_mutex);
-       return 0;
-}
-
-/*
- * scdrv_release
- *
- * Release a previously-reserved subchannel.
- */
-
-static int
-scdrv_release(struct inode *inode, struct file *file)
-{
-       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-       int rv;
-
-       /* free the interrupt */
-       free_irq(SGI_UART_VECTOR, sd);
-
-       /* ask SAL to close the subchannel */
-       rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
-
-       kfree(sd);
-       return rv;
-}
-
-/*
- * scdrv_read
- *
- * Called to read bytes from the open IRouter pipe.
- *
- */
-
-static inline int
-read_status_check(struct subch_data_s *sd, int *len)
-{
-       return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len);
-}
-
-static ssize_t
-scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
-{
-       int status;
-       int len;
-       unsigned long flags;
-       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-
-       /* try to get control of the read buffer */
-       if (down_trylock(&sd->sd_rbs)) {
-               /* somebody else has it now;
-                * if we're non-blocking, then exit...
-                */
-               if (file->f_flags & O_NONBLOCK) {
-                       return -EAGAIN;
-               }
-               /* ...or if we want to block, then do so here */
-               if (down_interruptible(&sd->sd_rbs)) {
-                       /* something went wrong with wait */
-                       return -ERESTARTSYS;
-               }
-       }
-
-       /* anything to read? */
-       len = CHUNKSIZE;
-       spin_lock_irqsave(&sd->sd_rlock, flags);
-       status = read_status_check(sd, &len);
-
-       /* if not, and we're blocking I/O, loop */
-       while (status < 0) {
-               DECLARE_WAITQUEUE(wait, current);
-
-               if (file->f_flags & O_NONBLOCK) {
-                       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-                       up(&sd->sd_rbs);
-                       return -EAGAIN;
-               }
-
-               len = CHUNKSIZE;
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&sd->sd_rq, &wait);
-               spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
-               schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
-
-               remove_wait_queue(&sd->sd_rq, &wait);
-               if (signal_pending(current)) {
-                       /* wait was interrupted */
-                       up(&sd->sd_rbs);
-                       return -ERESTARTSYS;
-               }
-
-               spin_lock_irqsave(&sd->sd_rlock, flags);
-               status = read_status_check(sd, &len);
-       }
-       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
-       if (len > 0) {
-               /* we read something in the last read_status_check(); copy
-                * it out to user space
-                */
-               if (count < len) {
-                       pr_debug("%s: only accepting %d of %d bytes\n",
-                                __func__, (int) count, len);
-               }
-               len = min((int) count, len);
-               if (copy_to_user(buf, sd->sd_rb, len))
-                       len = -EFAULT;
-       }
-
-       /* release the read buffer and wake anyone who might be
-        * waiting for it
-        */
-       up(&sd->sd_rbs);
-
-       /* return the number of characters read in */
-       return len;
-}
-
-/*
- * scdrv_write
- *
- * Writes a chunk of an IRouter packet (or other system controller data)
- * to the system controller.
- *
- */
-static inline int
-write_status_check(struct subch_data_s *sd, int count)
-{
-       return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count);
-}
-
-static ssize_t
-scdrv_write(struct file *file, const char __user *buf,
-           size_t count, loff_t *f_pos)
-{
-       unsigned long flags;
-       int status;
-       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-
-       /* try to get control of the write buffer */
-       if (down_trylock(&sd->sd_wbs)) {
-               /* somebody else has it now;
-                * if we're non-blocking, then exit...
-                */
-               if (file->f_flags & O_NONBLOCK) {
-                       return -EAGAIN;
-               }
-               /* ...or if we want to block, then do so here */
-               if (down_interruptible(&sd->sd_wbs)) {
-                       /* something went wrong with wait */
-                       return -ERESTARTSYS;
-               }
-       }
-
-       count = min((int) count, CHUNKSIZE);
-       if (copy_from_user(sd->sd_wb, buf, count)) {
-               up(&sd->sd_wbs);
-               return -EFAULT;
-       }
-
-       /* try to send the buffer */
-       spin_lock_irqsave(&sd->sd_wlock, flags);
-       status = write_status_check(sd, count);
-
-       /* if we failed, and we want to block, then loop */
-       while (status <= 0) {
-               DECLARE_WAITQUEUE(wait, current);
-
-               if (file->f_flags & O_NONBLOCK) {
-                       spin_unlock_irqrestore(&sd->sd_wlock, flags);
-                       up(&sd->sd_wbs);
-                       return -EAGAIN;
-               }
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&sd->sd_wq, &wait);
-               spin_unlock_irqrestore(&sd->sd_wlock, flags);
-
-               schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
-
-               remove_wait_queue(&sd->sd_wq, &wait);
-               if (signal_pending(current)) {
-                       /* wait was interrupted */
-                       up(&sd->sd_wbs);
-                       return -ERESTARTSYS;
-               }
-
-               spin_lock_irqsave(&sd->sd_wlock, flags);
-               status = write_status_check(sd, count);
-       }
-       spin_unlock_irqrestore(&sd->sd_wlock, flags);
-
-       /* release the write buffer and wake anyone who's waiting for it */
-       up(&sd->sd_wbs);
-
-       /* return the number of characters accepted (should be the complete
-        * "chunk" as requested)
-        */
-       if ((status >= 0) && (status < count)) {
-               pr_debug("Didn't accept the full chunk; %d of %d\n",
-                        status, (int) count);
-       }
-       return status;
-}
-
-static __poll_t
-scdrv_poll(struct file *file, struct poll_table_struct *wait)
-{
-       __poll_t mask = 0;
-       int status = 0;
-       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-       unsigned long flags;
-
-       poll_wait(file, &sd->sd_rq, wait);
-       poll_wait(file, &sd->sd_wq, wait);
-
-       spin_lock_irqsave(&sd->sd_rlock, flags);
-       spin_lock(&sd->sd_wlock);
-       status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
-       spin_unlock(&sd->sd_wlock);
-       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
-       if (status > 0) {
-               if (status & SAL_IROUTER_INTR_RECV) {
-                       mask |= EPOLLIN | EPOLLRDNORM;
-               }
-               if (status & SAL_IROUTER_INTR_XMIT) {
-                       mask |= EPOLLOUT | EPOLLWRNORM;
-               }
-       }
-
-       return mask;
-}
-
-static const struct file_operations scdrv_fops = {
-       .owner =        THIS_MODULE,
-       .read =         scdrv_read,
-       .write =        scdrv_write,
-       .poll =         scdrv_poll,
-       .open =         scdrv_open,
-       .release =      scdrv_release,
-       .llseek =       noop_llseek,
-};
-
-static struct class *snsc_class;
-
-/*
- * scdrv_init
- *
- * Called at boot time to initialize the system controller communication
- * facility.
- */
-int __init
-scdrv_init(void)
-{
-       geoid_t geoid;
-       cnodeid_t cnode;
-       char devname[32];
-       char *devnamep;
-       struct sysctl_data_s *scd;
-       void *salbuf;
-       dev_t first_dev, dev;
-       nasid_t event_nasid;
-
-       if (!ia64_platform_is("sn2"))
-               return -ENODEV;
-
-       event_nasid = ia64_sn_get_console_nasid();
-
-       snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
-       if (IS_ERR(snsc_class)) {
-               printk("%s: failed to allocate class\n", __func__);
-               return PTR_ERR(snsc_class);
-       }
-
-       if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
-                               SYSCTL_BASENAME) < 0) {
-               printk("%s: failed to register SN system controller device\n",
-                      __func__);
-               return -ENODEV;
-       }
-
-       for (cnode = 0; cnode < num_cnodes; cnode++) {
-                       geoid = cnodeid_get_geoid(cnode);
-                       devnamep = devname;
-                       format_module_id(devnamep, geo_module(geoid),
-                                        MODULE_FORMAT_BRIEF);
-                       devnamep = devname + strlen(devname);
-                       sprintf(devnamep, "^%d#%d", geo_slot(geoid),
-                               geo_slab(geoid));
-
-                       /* allocate sysctl device data */
-                       scd = kzalloc(sizeof (struct sysctl_data_s),
-                                     GFP_KERNEL);
-                       if (!scd) {
-                               printk("%s: failed to allocate device info"
-                                      "for %s/%s\n", __func__,
-                                      SYSCTL_BASENAME, devname);
-                               continue;
-                       }
-
-                       /* initialize sysctl device data fields */
-                       scd->scd_nasid = cnodeid_to_nasid(cnode);
-                       if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
-                               printk("%s: failed to allocate driver buffer"
-                                      "(%s%s)\n", __func__,
-                                      SYSCTL_BASENAME, devname);
-                               kfree(scd);
-                               continue;
-                       }
-
-                       if (ia64_sn_irtr_init(scd->scd_nasid, salbuf,
-                                             SCDRV_BUFSZ) < 0) {
-                               printk
-                                   ("%s: failed to initialize SAL for"
-                                    " system controller communication"
-                                    " (%s/%s): outdated PROM?\n",
-                                    __func__, SYSCTL_BASENAME, devname);
-                               kfree(scd);
-                               kfree(salbuf);
-                               continue;
-                       }
-
-                       dev = first_dev + cnode;
-                       cdev_init(&scd->scd_cdev, &scdrv_fops);
-                       if (cdev_add(&scd->scd_cdev, dev, 1)) {
-                               printk("%s: failed to register system"
-                                      " controller device (%s%s)\n",
-                                      __func__, SYSCTL_BASENAME, devname);
-                               kfree(scd);
-                               kfree(salbuf);
-                               continue;
-                       }
-
-                       device_create(snsc_class, NULL, dev, NULL,
-                                     "%s", devname);
-
-                       ia64_sn_irtr_intr_enable(scd->scd_nasid,
-                                                0 /*ignored */ ,
-                                                SAL_IROUTER_INTR_RECV);
-
-                        /* on the console nasid, prepare to receive
-                         * system controller environmental events
-                         */
-                        if(scd->scd_nasid == event_nasid) {
-                                scdrv_event_init(scd);
-                        }
-       }
-       return 0;
-}
-device_initcall(scdrv_init);
diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h
deleted file mode 100644 (file)
index e8c52c8..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * This file contains macros and data types for communication with the
- * system controllers in SGI SN systems.
- */
-
-#ifndef _SN_SYSCTL_H_
-#define _SN_SYSCTL_H_
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/semaphore.h>
-#include <asm/sn/types.h>
-
-#define CHUNKSIZE 127
-
-/* This structure is used to track an open subchannel. */
-struct subch_data_s {
-       nasid_t sd_nasid;       /* node on which the subchannel was opened */
-       int sd_subch;           /* subchannel number */
-       spinlock_t sd_rlock;    /* monitor lock for rsv */
-       spinlock_t sd_wlock;    /* monitor lock for wsv */
-       wait_queue_head_t sd_rq;        /* wait queue for readers */
-       wait_queue_head_t sd_wq;        /* wait queue for writers */
-       struct semaphore sd_rbs;        /* semaphore for read buffer */
-       struct semaphore sd_wbs;        /* semaphore for write buffer */
-
-       char sd_rb[CHUNKSIZE];  /* read buffer */
-       char sd_wb[CHUNKSIZE];  /* write buffer */
-};
-
-struct sysctl_data_s {
-       struct cdev scd_cdev;   /* Character device info */
-       nasid_t scd_nasid;      /* Node on which subchannels are opened. */
-};
-
-
-/* argument types */
-#define IR_ARG_INT              0x00    /* 4-byte integer (big-endian)  */
-#define IR_ARG_ASCII            0x01    /* null-terminated ASCII string */
-#define IR_ARG_UNKNOWN          0x80    /* unknown data type.  The low
-                                         * 7 bits will contain the data
-                                         * length.                      */
-#define IR_ARG_UNKNOWN_LENGTH_MASK     0x7f
-
-
-/* system controller event codes */
-#define EV_CLASS_MASK          0xf000ul
-#define EV_SEVERITY_MASK       0x0f00ul
-#define EV_COMPONENT_MASK      0x00fful
-
-#define EV_CLASS_POWER         0x1000ul
-#define EV_CLASS_FAN           0x2000ul
-#define EV_CLASS_TEMP          0x3000ul
-#define EV_CLASS_ENV           0x4000ul
-#define EV_CLASS_TEST_FAULT    0x5000ul
-#define EV_CLASS_TEST_WARNING  0x6000ul
-#define EV_CLASS_PWRD_NOTIFY   0x8000ul
-
-/* ENV class codes */
-#define ENV_PWRDN_PEND         0x4101ul
-
-#define EV_SEVERITY_POWER_STABLE       0x0000ul
-#define EV_SEVERITY_POWER_LOW_WARNING  0x0100ul
-#define EV_SEVERITY_POWER_HIGH_WARNING 0x0200ul
-#define EV_SEVERITY_POWER_HIGH_FAULT   0x0300ul
-#define EV_SEVERITY_POWER_LOW_FAULT    0x0400ul
-
-#define EV_SEVERITY_FAN_STABLE         0x0000ul
-#define EV_SEVERITY_FAN_WARNING                0x0100ul
-#define EV_SEVERITY_FAN_FAULT          0x0200ul
-
-#define EV_SEVERITY_TEMP_STABLE                0x0000ul
-#define EV_SEVERITY_TEMP_ADVISORY      0x0100ul
-#define EV_SEVERITY_TEMP_CRITICAL      0x0200ul
-#define EV_SEVERITY_TEMP_FAULT         0x0300ul
-
-void scdrv_event_init(struct sysctl_data_s *);
-
-#endif /* _SN_SYSCTL_H_ */
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
deleted file mode 100644 (file)
index e452673..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * System controller event handler
- *
- * These routines deal with environmental events arriving from the
- * system controllers.
- */
-
-#include <linux/interrupt.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/unaligned.h>
-#include "snsc.h"
-
-static struct subch_data_s *event_sd;
-
-void scdrv_event(unsigned long);
-DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
-
-/*
- * scdrv_event_interrupt
- *
- * Pull incoming environmental events off the physical link to the
- * system controller and put them in a temporary holding area in SAL.
- * Schedule scdrv_event() to move them along to their ultimate
- * destination.
- */
-static irqreturn_t
-scdrv_event_interrupt(int irq, void *subch_data)
-{
-       struct subch_data_s *sd = subch_data;
-       unsigned long flags;
-       int status;
-
-       spin_lock_irqsave(&sd->sd_rlock, flags);
-       status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
-
-       if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) {
-               tasklet_schedule(&sn_sysctl_event);
-       }
-       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-       return IRQ_HANDLED;
-}
-
-
-/*
- * scdrv_parse_event
- *
- * Break an event (as read from SAL) into useful pieces so we can decide
- * what to do with it.
- */
-static int
-scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
-{
-       char *desc_end;
-
-       /* record event source address */
-       *src = get_unaligned_be32(event);
-       event += 4;                     /* move on to event code */
-
-       /* record the system controller's event code */
-       *code = get_unaligned_be32(event);
-       event += 4;                     /* move on to event arguments */
-
-       /* how many arguments are in the packet? */
-       if (*event++ != 2) {
-               /* if not 2, give up */
-               return -1;
-       }
-
-       /* parse out the ESP code */
-       if (*event++ != IR_ARG_INT) {
-               /* not an integer argument, so give up */
-               return -1;
-       }
-       *esp_code = get_unaligned_be32(event);
-       event += 4;
-
-       /* parse out the event description */
-       if (*event++ != IR_ARG_ASCII) {
-               /* not an ASCII string, so give up */
-               return -1;
-       }
-       event[CHUNKSIZE-1] = '\0';      /* ensure this string ends! */
-       event += 2;                     /* skip leading CR/LF */
-       desc_end = desc + sprintf(desc, "%s", event);
-
-       /* strip trailing CR/LF (if any) */
-       for (desc_end--;
-            (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa));
-            desc_end--) {
-               *desc_end = '\0';
-       }
-
-       return 0;
-}
-
-
-/*
- * scdrv_event_severity
- *
- * Figure out how urgent a message we should write to the console/syslog
- * via printk.
- */
-static char *
-scdrv_event_severity(int code)
-{
-       int ev_class = (code & EV_CLASS_MASK);
-       int ev_severity = (code & EV_SEVERITY_MASK);
-       char *pk_severity = KERN_NOTICE;
-
-       switch (ev_class) {
-       case EV_CLASS_POWER:
-               switch (ev_severity) {
-               case EV_SEVERITY_POWER_LOW_WARNING:
-               case EV_SEVERITY_POWER_HIGH_WARNING:
-                       pk_severity = KERN_WARNING;
-                       break;
-               case EV_SEVERITY_POWER_HIGH_FAULT:
-               case EV_SEVERITY_POWER_LOW_FAULT:
-                       pk_severity = KERN_ALERT;
-                       break;
-               }
-               break;
-       case EV_CLASS_FAN:
-               switch (ev_severity) {
-               case EV_SEVERITY_FAN_WARNING:
-                       pk_severity = KERN_WARNING;
-                       break;
-               case EV_SEVERITY_FAN_FAULT:
-                       pk_severity = KERN_CRIT;
-                       break;
-               }
-               break;
-       case EV_CLASS_TEMP:
-               switch (ev_severity) {
-               case EV_SEVERITY_TEMP_ADVISORY:
-                       pk_severity = KERN_WARNING;
-                       break;
-               case EV_SEVERITY_TEMP_CRITICAL:
-                       pk_severity = KERN_CRIT;
-                       break;
-               case EV_SEVERITY_TEMP_FAULT:
-                       pk_severity = KERN_ALERT;
-                       break;
-               }
-               break;
-       case EV_CLASS_ENV:
-               pk_severity = KERN_ALERT;
-               break;
-       case EV_CLASS_TEST_FAULT:
-               pk_severity = KERN_ALERT;
-               break;
-       case EV_CLASS_TEST_WARNING:
-               pk_severity = KERN_WARNING;
-               break;
-       case EV_CLASS_PWRD_NOTIFY:
-               pk_severity = KERN_ALERT;
-               break;
-       }
-
-       return pk_severity;
-}
-
-
-/*
- * scdrv_dispatch_event
- *
- * Do the right thing with an incoming event.  That's often nothing
- * more than printing it to the system log.  For power-down notifications
- * we start a graceful shutdown.
- */
-static void
-scdrv_dispatch_event(char *event, int len)
-{
-       static int snsc_shutting_down = 0;
-       int code, esp_code, src, class;
-       char desc[CHUNKSIZE];
-       char *severity;
-
-       if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) {
-               /* ignore uninterpretible event */
-               return;
-       }
-
-       /* how urgent is the message? */
-       severity = scdrv_event_severity(code);
-
-       class = (code & EV_CLASS_MASK);
-
-       if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) {
-               if (snsc_shutting_down)
-                       return;
-
-               snsc_shutting_down = 1;
-
-               /* give a message for each type of event */
-               if (class == EV_CLASS_PWRD_NOTIFY)
-                       printk(KERN_NOTICE "Power off indication received."
-                              " Sending SIGPWR to init...\n");
-               else if (code == ENV_PWRDN_PEND)
-                       printk(KERN_CRIT "WARNING: Shutting down the system"
-                              " due to a critical environmental condition."
-                              " Sending SIGPWR to init...\n");
-
-               /* give a SIGPWR signal to init proc */
-               kill_cad_pid(SIGPWR, 0);
-       } else {
-               /* print to system log */
-               printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
-       }
-}
-
-
-/*
- * scdrv_event
- *
- * Called as a tasklet when an event arrives from the L1.  Read the event
- * from where it's temporarily stored in SAL and call scdrv_dispatch_event()
- * to send it on its way.  Keep trying to read events until SAL indicates
- * that there are no more immediately available.
- */
-void
-scdrv_event(unsigned long dummy)
-{
-       int status;
-       int len;
-       unsigned long flags;
-       struct subch_data_s *sd = event_sd;
-
-       /* anything to read? */
-       len = CHUNKSIZE;
-       spin_lock_irqsave(&sd->sd_rlock, flags);
-       status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
-                                  sd->sd_rb, &len);
-
-       while (!(status < 0)) {
-               spin_unlock_irqrestore(&sd->sd_rlock, flags);
-               scdrv_dispatch_event(sd->sd_rb, len);
-               len = CHUNKSIZE;
-               spin_lock_irqsave(&sd->sd_rlock, flags);
-               status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
-                                          sd->sd_rb, &len);
-       }
-       spin_unlock_irqrestore(&sd->sd_rlock, flags);
-}
-
-
-/*
- * scdrv_event_init
- *
- * Sets up a system controller subchannel to begin receiving event
- * messages. This is sort of a specialized version of scdrv_open()
- * in drivers/char/sn_sysctl.c.
- */
-void
-scdrv_event_init(struct sysctl_data_s *scd)
-{
-       int rv;
-
-       event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
-       if (event_sd == NULL) {
-               printk(KERN_WARNING "%s: couldn't allocate subchannel info"
-                      " for event monitoring\n", __func__);
-               return;
-       }
-
-       /* initialize subch_data_s fields */
-       event_sd->sd_nasid = scd->scd_nasid;
-       spin_lock_init(&event_sd->sd_rlock);
-
-       /* ask the system controllers to send events to this node */
-       event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid);
-
-       if (event_sd->sd_subch < 0) {
-               kfree(event_sd);
-               printk(KERN_WARNING "%s: couldn't open event subchannel\n",
-                      __func__);
-               return;
-       }
-
-       /* hook event subchannel up to the system controller interrupt */
-       rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
-                        IRQF_SHARED, "system controller events", event_sd);
-       if (rv) {
-               printk(KERN_WARNING "%s: irq request failed (%d)\n",
-                      __func__, rv);
-               ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
-               kfree(event_sd);
-               return;
-       }
-}
index 88a3c06..9c37047 100644 (file)
@@ -164,6 +164,11 @@ config TCG_VTPM_PROXY
          /dev/vtpmX and a server-side file descriptor on which the vTPM
          can receive commands.
 
+config TCG_FTPM_TEE
+       tristate "TEE based fTPM Interface"
+       depends on TEE && OPTEE
+       help
+         This driver proxies for firmware TPM running in TEE.
 
 source "drivers/char/tpm/st33zp24/Kconfig"
 endif # TCG_TPM
index a01c4ca..c354cdf 100644 (file)
@@ -33,3 +33,4 @@ obj-$(CONFIG_TCG_TIS_ST33ZP24) += st33zp24/
 obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
 obj-$(CONFIG_TCG_CRB) += tpm_crb.o
 obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o
+obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o
index 4838c6a..3d6d394 100644 (file)
@@ -287,12 +287,9 @@ static void tpm_devs_release(struct device *dev)
  * @dev: device to which the chip is associated.
  *
  * Issues a TPM2_Shutdown command prior to loss of power, as required by the
- * TPM 2.0 spec.
- * Then, calls bus- and device- specific shutdown code.
+ * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code.
  *
- * XXX: This codepath relies on the fact that sysfs is not enabled for
- * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
- * has sysfs support enabled before TPM sysfs's implicit locking is fixed.
+ * Return: always 0 (i.e. success)
  */
 static int tpm_class_shutdown(struct device *dev)
 {
index d9caedd..edfa891 100644 (file)
@@ -329,16 +329,9 @@ static const struct attribute_group tpm_dev_group = {
 
 void tpm_sysfs_add_device(struct tpm_chip *chip)
 {
-       /* XXX: If you wish to remove this restriction, you must first update
-        * tpm_sysfs to explicitly lock chip->ops.
-        */
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                return;
 
-       /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
-        * is called before ops is null'd and the sysfs core synchronizes this
-        * removal so that no callbacks are running or can run again
-        */
        WARN_ON(chip->groups_cnt != 0);
        chip->groups[chip->groups_cnt++] = &tpm_dev_group;
 }
diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c
new file mode 100644 (file)
index 0000000..6640a14
--- /dev/null
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation
+ *
+ * Implements a firmware TPM as described here:
+ * https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/
+ *
+ * A reference implementation is available here:
+ * https://github.com/microsoft/ms-tpm-20-ref/tree/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM
+ */
+
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/tee_drv.h>
+#include <linux/tpm.h>
+#include <linux/uuid.h>
+
+#include "tpm.h"
+#include "tpm_ftpm_tee.h"
+
+/*
+ * TA_FTPM_UUID: BC50D971-D4C9-42C4-82CB-343FB7F37896
+ *
+ * Randomly generated, and must correspond to the GUID on the TA side.
+ * Defined here in the reference implementation:
+ * https://github.com/microsoft/ms-tpm-20-ref/blob/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM/include/fTPM.h#L42
+ */
+static const uuid_t ftpm_ta_uuid =
+       UUID_INIT(0xBC50D971, 0xD4C9, 0x42C4,
+                 0x82, 0xCB, 0x34, 0x3F, 0xB7, 0xF3, 0x78, 0x96);
+
+/**
+ * ftpm_tee_tpm_op_recv - retrieve fTPM response.
+ * @chip:      the tpm_chip description as specified in driver/char/tpm/tpm.h.
+ * @buf:       the buffer to store data.
+ * @count:     the number of bytes to read.
+ *
+ * Return:
+ *     In case of success the number of bytes received.
+ *     On failure, -errno.
+ */
+static int ftpm_tee_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
+       size_t len;
+
+       len = pvt_data->resp_len;
+       if (count < len) {
+               dev_err(&chip->dev,
+                       "%s: Invalid size in recv: count=%zd, resp_len=%zd\n",
+                       __func__, count, len);
+               return -EIO;
+       }
+
+       memcpy(buf, pvt_data->resp_buf, len);
+       pvt_data->resp_len = 0;
+
+       return len;
+}
+
+/**
+ * ftpm_tee_tpm_op_send - send TPM commands through the TEE shared memory.
+ * @chip:      the tpm_chip description as specified in driver/char/tpm/tpm.h
+ * @buf:       the buffer to send.
+ * @len:       the number of bytes to send.
+ *
+ * Return:
+ *     In case of success, returns 0.
+ *     On failure, -errno
+ */
+static int ftpm_tee_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(chip->dev.parent);
+       size_t resp_len;
+       int rc;
+       u8 *temp_buf;
+       struct tpm_header *resp_header;
+       struct tee_ioctl_invoke_arg transceive_args;
+       struct tee_param command_params[4];
+       struct tee_shm *shm = pvt_data->shm;
+
+       if (len > MAX_COMMAND_SIZE) {
+               dev_err(&chip->dev,
+                       "%s: len=%zd exceeds MAX_COMMAND_SIZE supported by fTPM TA\n",
+                       __func__, len);
+               return -EIO;
+       }
+
+       memset(&transceive_args, 0, sizeof(transceive_args));
+       memset(command_params, 0, sizeof(command_params));
+       pvt_data->resp_len = 0;
+
+       /* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of fTPM TA */
+       transceive_args = (struct tee_ioctl_invoke_arg) {
+               .func = FTPM_OPTEE_TA_SUBMIT_COMMAND,
+               .session = pvt_data->session,
+               .num_params = 4,
+       };
+
+       /* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */
+       command_params[0] = (struct tee_param) {
+               .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+               .u.memref = {
+                       .shm = shm,
+                       .size = len,
+                       .shm_offs = 0,
+               },
+       };
+
+       temp_buf = tee_shm_get_va(shm, 0);
+       if (IS_ERR(temp_buf)) {
+               dev_err(&chip->dev, "%s: tee_shm_get_va failed for transmit\n",
+                       __func__);
+               return PTR_ERR(temp_buf);
+       }
+       memset(temp_buf, 0, (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE));
+       memcpy(temp_buf, buf, len);
+
+       command_params[1] = (struct tee_param) {
+               .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+               .u.memref = {
+                       .shm = shm,
+                       .size = MAX_RESPONSE_SIZE,
+                       .shm_offs = MAX_COMMAND_SIZE,
+               },
+       };
+
+       rc = tee_client_invoke_func(pvt_data->ctx, &transceive_args,
+                                   command_params);
+       if ((rc < 0) || (transceive_args.ret != 0)) {
+               dev_err(&chip->dev, "%s: SUBMIT_COMMAND invoke error: 0x%x\n",
+                       __func__, transceive_args.ret);
+               return (rc < 0) ? rc : transceive_args.ret;
+       }
+
+       temp_buf = tee_shm_get_va(shm, command_params[1].u.memref.shm_offs);
+       if (IS_ERR(temp_buf)) {
+               dev_err(&chip->dev, "%s: tee_shm_get_va failed for receive\n",
+                       __func__);
+               return PTR_ERR(temp_buf);
+       }
+
+       resp_header = (struct tpm_header *)temp_buf;
+       resp_len = be32_to_cpu(resp_header->length);
+
+       /* sanity check resp_len */
+       if (resp_len < TPM_HEADER_SIZE) {
+               dev_err(&chip->dev, "%s: tpm response header too small\n",
+                       __func__);
+               return -EIO;
+       }
+       if (resp_len > MAX_RESPONSE_SIZE) {
+               dev_err(&chip->dev,
+                       "%s: resp_len=%zd exceeds MAX_RESPONSE_SIZE\n",
+                       __func__, resp_len);
+               return -EIO;
+       }
+
+       /* sanity checks look good, cache the response */
+       memcpy(pvt_data->resp_buf, temp_buf, resp_len);
+       pvt_data->resp_len = resp_len;
+
+       return 0;
+}
+
+static void ftpm_tee_tpm_op_cancel(struct tpm_chip *chip)
+{
+       /* not supported */
+}
+
+static u8 ftpm_tee_tpm_op_status(struct tpm_chip *chip)
+{
+       return 0;
+}
+
+static bool ftpm_tee_tpm_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return 0;
+}
+
+static const struct tpm_class_ops ftpm_tee_tpm_ops = {
+       .flags = TPM_OPS_AUTO_STARTUP,
+       .recv = ftpm_tee_tpm_op_recv,
+       .send = ftpm_tee_tpm_op_send,
+       .cancel = ftpm_tee_tpm_op_cancel,
+       .status = ftpm_tee_tpm_op_status,
+       .req_complete_mask = 0,
+       .req_complete_val = 0,
+       .req_canceled = ftpm_tee_tpm_req_canceled,
+};
+
+/*
+ * Check whether this driver supports the fTPM TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+       /*
+        * Currently this driver only support GP Complaint OPTEE based fTPM TA
+        */
+       if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
+               (ver->gen_caps & TEE_GEN_CAP_GP))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * ftpm_tee_probe - initialize the fTPM
+ * @pdev: the platform_device description.
+ *
+ * Return:
+ *     On success, 0. On failure, -errno.
+ */
+static int ftpm_tee_probe(struct platform_device *pdev)
+{
+       int rc;
+       struct tpm_chip *chip;
+       struct device *dev = &pdev->dev;
+       struct ftpm_tee_private *pvt_data = NULL;
+       struct tee_ioctl_open_session_arg sess_arg;
+
+       pvt_data = devm_kzalloc(dev, sizeof(struct ftpm_tee_private),
+                               GFP_KERNEL);
+       if (!pvt_data)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, pvt_data);
+
+       /* Open context with TEE driver */
+       pvt_data->ctx = tee_client_open_context(NULL, ftpm_tee_match, NULL,
+                                               NULL);
+       if (IS_ERR(pvt_data->ctx)) {
+               if (PTR_ERR(pvt_data->ctx) == -ENOENT)
+                       return -EPROBE_DEFER;
+               dev_err(dev, "%s: tee_client_open_context failed\n", __func__);
+               return PTR_ERR(pvt_data->ctx);
+       }
+
+       /* Open a session with fTPM TA */
+       memset(&sess_arg, 0, sizeof(sess_arg));
+       memcpy(sess_arg.uuid, ftpm_ta_uuid.b, TEE_IOCTL_UUID_LEN);
+       sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+       sess_arg.num_params = 0;
+
+       rc = tee_client_open_session(pvt_data->ctx, &sess_arg, NULL);
+       if ((rc < 0) || (sess_arg.ret != 0)) {
+               dev_err(dev, "%s: tee_client_open_session failed, err=%x\n",
+                       __func__, sess_arg.ret);
+               rc = -EINVAL;
+               goto out_tee_session;
+       }
+       pvt_data->session = sess_arg.session;
+
+       /* Allocate dynamic shared memory with fTPM TA */
+       pvt_data->shm = tee_shm_alloc(pvt_data->ctx,
+                                     MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE,
+                                     TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+       if (IS_ERR(pvt_data->shm)) {
+               dev_err(dev, "%s: tee_shm_alloc failed\n", __func__);
+               rc = -ENOMEM;
+               goto out_shm_alloc;
+       }
+
+       /* Allocate new struct tpm_chip instance */
+       chip = tpm_chip_alloc(dev, &ftpm_tee_tpm_ops);
+       if (IS_ERR(chip)) {
+               dev_err(dev, "%s: tpm_chip_alloc failed\n", __func__);
+               rc = PTR_ERR(chip);
+               goto out_chip_alloc;
+       }
+
+       pvt_data->chip = chip;
+       pvt_data->chip->flags |= TPM_CHIP_FLAG_TPM2;
+
+       /* Create a character device for the fTPM */
+       rc = tpm_chip_register(pvt_data->chip);
+       if (rc) {
+               dev_err(dev, "%s: tpm_chip_register failed with rc=%d\n",
+                       __func__, rc);
+               goto out_chip;
+       }
+
+       return 0;
+
+out_chip:
+       put_device(&pvt_data->chip->dev);
+out_chip_alloc:
+       tee_shm_free(pvt_data->shm);
+out_shm_alloc:
+       tee_client_close_session(pvt_data->ctx, pvt_data->session);
+out_tee_session:
+       tee_client_close_context(pvt_data->ctx);
+
+       return rc;
+}
+
+/**
+ * ftpm_tee_remove - remove the TPM device
+ * @pdev: the platform_device description.
+ *
+ * Return:
+ *     0 always.
+ */
+static int ftpm_tee_remove(struct platform_device *pdev)
+{
+       struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
+
+       /* Release the chip */
+       tpm_chip_unregister(pvt_data->chip);
+
+       /* frees chip */
+       put_device(&pvt_data->chip->dev);
+
+       /* Free the shared memory pool */
+       tee_shm_free(pvt_data->shm);
+
+       /* close the existing session with fTPM TA*/
+       tee_client_close_session(pvt_data->ctx, pvt_data->session);
+
+       /* close the context with TEE driver */
+       tee_client_close_context(pvt_data->ctx);
+
+       /* memory allocated with devm_kzalloc() is freed automatically */
+
+       return 0;
+}
+
+static const struct of_device_id of_ftpm_tee_ids[] = {
+       { .compatible = "microsoft,ftpm" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
+
+static struct platform_driver ftpm_tee_driver = {
+       .driver = {
+               .name = "ftpm-tee",
+               .of_match_table = of_match_ptr(of_ftpm_tee_ids),
+       },
+       .probe = ftpm_tee_probe,
+       .remove = ftpm_tee_remove,
+};
+
+module_platform_driver(ftpm_tee_driver);
+
+MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
+MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/tpm/tpm_ftpm_tee.h b/drivers/char/tpm/tpm_ftpm_tee.h
new file mode 100644 (file)
index 0000000..f98daa7
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation
+ */
+
+#ifndef __TPM_FTPM_TEE_H__
+#define __TPM_FTPM_TEE_H__
+
+#include <linux/tee_drv.h>
+#include <linux/tpm.h>
+#include <linux/uuid.h>
+
+/* The TAFs ID implemented in this TA */
+#define FTPM_OPTEE_TA_SUBMIT_COMMAND  (0)
+#define FTPM_OPTEE_TA_EMULATE_PPI     (1)
+
+/* max. buffer size supported by fTPM  */
+#define MAX_COMMAND_SIZE       4096
+#define MAX_RESPONSE_SIZE      4096
+
+/**
+ * struct ftpm_tee_private - fTPM's private data
+ * @chip:     struct tpm_chip instance registered with tpm framework.
+ * @state:    internal state
+ * @session:  fTPM TA session identifier.
+ * @resp_len: cached response buffer length.
+ * @resp_buf: cached response buffer.
+ * @ctx:      TEE context handler.
+ * @shm:      Memory pool shared with fTPM TA in TEE.
+ */
+struct ftpm_tee_private {
+       struct tpm_chip *chip;
+       u32 session;
+       size_t resp_len;
+       u8 resp_buf[MAX_RESPONSE_SIZE];
+       struct tee_context *ctx;
+       struct tee_shm *shm;
+};
+
+#endif /* __TPM_FTPM_TEE_H__ */
index c3181ea..270f43a 100644 (file)
@@ -980,6 +980,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                        goto out_err;
                }
 
+               tpm_chip_start(chip);
+               chip->flags |= TPM_CHIP_FLAG_IRQ;
                if (irq) {
                        tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
                                                 irq);
@@ -989,6 +991,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                } else {
                        tpm_tis_probe_irq(chip, intmask);
                }
+               tpm_chip_stop(chip);
        }
 
        rc = tpm_chip_register(chip);
index c099070..1c46bab 100644 (file)
@@ -324,6 +324,25 @@ static struct clk_core *clk_core_lookup(const char *name)
        return NULL;
 }
 
+#ifdef CONFIG_OF
+static int of_parse_clkspec(const struct device_node *np, int index,
+                           const char *name, struct of_phandle_args *out_args);
+static struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec);
+#else
+static inline int of_parse_clkspec(const struct device_node *np, int index,
+                                  const char *name,
+                                  struct of_phandle_args *out_args)
+{
+       return -ENOENT;
+}
+static inline struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
+{
+       return ERR_PTR(-ENOENT);
+}
+#endif
+
 /**
  * clk_core_get - Find the clk_core parent of a clk
  * @core: clk to find parent of
@@ -355,8 +374,9 @@ static struct clk_core *clk_core_lookup(const char *name)
  *      };
  *
  * Returns: -ENOENT when the provider can't be found or the clk doesn't
- * exist in the provider. -EINVAL when the name can't be found. NULL when the
- * provider knows about the clk but it isn't provided on this system.
+ * exist in the provider or the name can't be found in the DT node or
+ * in a clkdev lookup. NULL when the provider knows about the clk but it
+ * isn't provided on this system.
  * A valid clk_core pointer when the clk can be found in the provider.
  */
 static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
@@ -367,17 +387,19 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
        struct device *dev = core->dev;
        const char *dev_id = dev ? dev_name(dev) : NULL;
        struct device_node *np = core->of_node;
+       struct of_phandle_args clkspec;
 
-       if (np && (name || index >= 0))
-               hw = of_clk_get_hw(np, index, name);
-
-       /*
-        * If the DT search above couldn't find the provider or the provider
-        * didn't know about this clk, fallback to looking up via clkdev based
-        * clk_lookups
-        */
-       if (PTR_ERR(hw) == -ENOENT && name)
+       if (np && (name || index >= 0) &&
+           !of_parse_clkspec(np, index, name, &clkspec)) {
+               hw = of_clk_get_hw_from_clkspec(&clkspec);
+               of_node_put(clkspec.np);
+       } else if (name) {
+               /*
+                * If the DT search above couldn't find the provider fallback to
+                * looking up via clkdev based clk_lookups.
+                */
                hw = clk_find_hw(dev_id, name);
+       }
 
        if (IS_ERR(hw))
                return ERR_CAST(hw);
@@ -401,7 +423,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
                        parent = ERR_PTR(-EPROBE_DEFER);
        } else {
                parent = clk_core_get(core, index);
-               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
+               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT && entry->name)
                        parent = clk_core_lookup(entry->name);
        }
 
@@ -1632,7 +1654,8 @@ static int clk_fetch_parent_index(struct clk_core *core,
                        break;
 
                /* Fallback to comparing globally unique names */
-               if (!strcmp(parent->name, core->parents[i].name))
+               if (core->parents[i].name &&
+                   !strcmp(parent->name, core->parents[i].name))
                        break;
        }
 
index 91db789..65c82d9 100644 (file)
@@ -14,7 +14,7 @@
 #include "clk-exynos5-subcmu.h"
 
 static struct samsung_clk_provider *ctx;
-static const struct exynos5_subcmu_info *cmu;
+static const struct exynos5_subcmu_info **cmu;
 static int nr_cmus;
 
 static void exynos5_subcmu_clk_save(void __iomem *base,
@@ -56,17 +56,17 @@ static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx,
  * when OF-core populates all device-tree nodes.
  */
 void exynos5_subcmus_init(struct samsung_clk_provider *_ctx, int _nr_cmus,
-                         const struct exynos5_subcmu_info *_cmu)
+                         const struct exynos5_subcmu_info **_cmu)
 {
        ctx = _ctx;
        cmu = _cmu;
        nr_cmus = _nr_cmus;
 
        for (; _nr_cmus--; _cmu++) {
-               exynos5_subcmu_defer_gate(ctx, _cmu->gate_clks,
-                                         _cmu->nr_gate_clks);
-               exynos5_subcmu_clk_save(ctx->reg_base, _cmu->suspend_regs,
-                                       _cmu->nr_suspend_regs);
+               exynos5_subcmu_defer_gate(ctx, (*_cmu)->gate_clks,
+                                         (*_cmu)->nr_gate_clks);
+               exynos5_subcmu_clk_save(ctx->reg_base, (*_cmu)->suspend_regs,
+                                       (*_cmu)->nr_suspend_regs);
        }
 }
 
@@ -163,9 +163,9 @@ static int __init exynos5_clk_probe(struct platform_device *pdev)
                if (of_property_read_string(np, "label", &name) < 0)
                        continue;
                for (i = 0; i < nr_cmus; i++)
-                       if (strcmp(cmu[i].pd_name, name) == 0)
+                       if (strcmp(cmu[i]->pd_name, name) == 0)
                                exynos5_clk_register_subcmu(&pdev->dev,
-                                                           &cmu[i], np);
+                                                           cmu[i], np);
        }
        return 0;
 }
index 755ee8a..9ae5356 100644 (file)
@@ -21,6 +21,6 @@ struct exynos5_subcmu_info {
 };
 
 void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus,
-                         const struct exynos5_subcmu_info *cmu);
+                         const struct exynos5_subcmu_info **cmu);
 
 #endif
index f2b8968..931c70a 100644 (file)
@@ -681,6 +681,10 @@ static const struct exynos5_subcmu_info exynos5250_disp_subcmu = {
        .pd_name        = "DISP1",
 };
 
+static const struct exynos5_subcmu_info *exynos5250_subcmus[] = {
+       &exynos5250_disp_subcmu,
+};
+
 static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = {
        /* sorted in descending order */
        /* PLL_36XX_RATE(rate, m, p, s, k) */
@@ -843,7 +847,8 @@ static void __init exynos5250_clk_init(struct device_node *np)
 
        samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
                               ARRAY_SIZE(exynos5250_clk_regs));
-       exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu);
+       exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
+                            exynos5250_subcmus);
 
        samsung_clk_of_add_provider(np, ctx);
 
index 01bca5a..7670cc5 100644 (file)
@@ -534,8 +534,6 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = {
                                GATE_BUS_TOP, 24, 0, 0),
        GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
                                GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
-       GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll",
-                       SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
 };
 
 static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
@@ -577,8 +575,13 @@ static const struct samsung_div_clock exynos5420_div_clks[] __initconst = {
 
 static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = {
        GATE(CLK_SECKEY, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0),
+       /* Maudio Block */
        GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
                        SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
+               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
+               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
 };
 
 static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
@@ -890,9 +893,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
        /* GSCL Block */
        DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2),
 
-       /* MSCL Block */
-       DIV(0, "dout_mscl_blk", "aclk400_mscl", DIV2_RATIO0, 28, 2),
-
        /* PSGEN */
        DIV(0, "dout_gen_blk", "mout_user_aclk266", DIV2_RATIO0, 8, 1),
        DIV(0, "dout_jpg_blk", "aclk166", DIV2_RATIO0, 20, 1),
@@ -1017,12 +1017,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
        GATE(CLK_SCLK_DP1, "sclk_dp1", "dout_dp1",
                        GATE_TOP_SCLK_DISP1, 20, CLK_SET_RATE_PARENT, 0),
 
-       /* Maudio Block */
-       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
-               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
-       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
-               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
-
        /* FSYS Block */
        GATE(CLK_TSI, "tsi", "aclk200_fsys", GATE_BUS_FSYS0, 0, 0, 0),
        GATE(CLK_PDMA0, "pdma0", "aclk200_fsys", GATE_BUS_FSYS0, 1, 0, 0),
@@ -1162,17 +1156,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
        GATE(CLK_FIMC_LITE3, "fimc_lite3", "aclk333_432_gscl",
                        GATE_IP_GSCL1, 17, 0, 0),
 
-       /* MSCL Block */
-       GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
-       GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
-       GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
-       GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "dout_mscl_blk",
-                       GATE_IP_MSCL, 8, 0, 0),
-       GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "dout_mscl_blk",
-                       GATE_IP_MSCL, 9, 0, 0),
-       GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk",
-                       GATE_IP_MSCL, 10, 0, 0),
-
        /* ISP */
        GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp",
                        GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0),
@@ -1281,32 +1264,103 @@ static struct exynos5_subcmu_reg_dump exynos5x_mfc_suspend_regs[] = {
        { DIV4_RATIO, 0, 0x3 },                 /* DIV dout_mfc_blk */
 };
 
-static const struct exynos5_subcmu_info exynos5x_subcmus[] = {
-       {
-               .div_clks       = exynos5x_disp_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_disp_div_clks),
-               .gate_clks      = exynos5x_disp_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_disp_gate_clks),
-               .suspend_regs   = exynos5x_disp_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs),
-               .pd_name        = "DISP",
-       }, {
-               .div_clks       = exynos5x_gsc_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_gsc_div_clks),
-               .gate_clks      = exynos5x_gsc_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_gsc_gate_clks),
-               .suspend_regs   = exynos5x_gsc_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs),
-               .pd_name        = "GSC",
-       }, {
-               .div_clks       = exynos5x_mfc_div_clks,
-               .nr_div_clks    = ARRAY_SIZE(exynos5x_mfc_div_clks),
-               .gate_clks      = exynos5x_mfc_gate_clks,
-               .nr_gate_clks   = ARRAY_SIZE(exynos5x_mfc_gate_clks),
-               .suspend_regs   = exynos5x_mfc_suspend_regs,
-               .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs),
-               .pd_name        = "MFC",
-       },
+static const struct samsung_gate_clock exynos5x_mscl_gate_clks[] __initconst = {
+       /* MSCL Block */
+       GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
+       GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
+       GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
+       GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "dout_mscl_blk",
+                       GATE_IP_MSCL, 8, 0, 0),
+       GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "dout_mscl_blk",
+                       GATE_IP_MSCL, 9, 0, 0),
+       GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk",
+                       GATE_IP_MSCL, 10, 0, 0),
+};
+
+static const struct samsung_div_clock exynos5x_mscl_div_clks[] __initconst = {
+       DIV(0, "dout_mscl_blk", "aclk400_mscl", DIV2_RATIO0, 28, 2),
+};
+
+static struct exynos5_subcmu_reg_dump exynos5x_mscl_suspend_regs[] = {
+       { GATE_IP_MSCL, 0xffffffff, 0xffffffff }, /* MSCL gates */
+       { SRC_TOP3, 0, BIT(4) },                /* MUX mout_user_aclk400_mscl */
+       { DIV2_RATIO0, 0, 0x30000000 },         /* DIV dout_mscl_blk */
+};
+
+static const struct samsung_gate_clock exynos5800_mau_gate_clks[] __initconst = {
+       GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll",
+                       SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
+               GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
+       GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
+               GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
+};
+
+static struct exynos5_subcmu_reg_dump exynos5800_mau_suspend_regs[] = {
+       { SRC_TOP9, 0, BIT(8) },        /* MUX mout_user_mau_epll */
+};
+
+static const struct exynos5_subcmu_info exynos5x_disp_subcmu = {
+       .div_clks       = exynos5x_disp_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_disp_div_clks),
+       .gate_clks      = exynos5x_disp_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_disp_gate_clks),
+       .suspend_regs   = exynos5x_disp_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs),
+       .pd_name        = "DISP",
+};
+
+static const struct exynos5_subcmu_info exynos5x_gsc_subcmu = {
+       .div_clks       = exynos5x_gsc_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_gsc_div_clks),
+       .gate_clks      = exynos5x_gsc_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_gsc_gate_clks),
+       .suspend_regs   = exynos5x_gsc_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs),
+       .pd_name        = "GSC",
+};
+
+static const struct exynos5_subcmu_info exynos5x_mfc_subcmu = {
+       .div_clks       = exynos5x_mfc_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_mfc_div_clks),
+       .gate_clks      = exynos5x_mfc_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_mfc_gate_clks),
+       .suspend_regs   = exynos5x_mfc_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs),
+       .pd_name        = "MFC",
+};
+
+static const struct exynos5_subcmu_info exynos5x_mscl_subcmu = {
+       .div_clks       = exynos5x_mscl_div_clks,
+       .nr_div_clks    = ARRAY_SIZE(exynos5x_mscl_div_clks),
+       .gate_clks      = exynos5x_mscl_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5x_mscl_gate_clks),
+       .suspend_regs   = exynos5x_mscl_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5x_mscl_suspend_regs),
+       .pd_name        = "MSC",
+};
+
+static const struct exynos5_subcmu_info exynos5800_mau_subcmu = {
+       .gate_clks      = exynos5800_mau_gate_clks,
+       .nr_gate_clks   = ARRAY_SIZE(exynos5800_mau_gate_clks),
+       .suspend_regs   = exynos5800_mau_suspend_regs,
+       .nr_suspend_regs = ARRAY_SIZE(exynos5800_mau_suspend_regs),
+       .pd_name        = "MAU",
+};
+
+static const struct exynos5_subcmu_info *exynos5x_subcmus[] = {
+       &exynos5x_disp_subcmu,
+       &exynos5x_gsc_subcmu,
+       &exynos5x_mfc_subcmu,
+       &exynos5x_mscl_subcmu,
+};
+
+static const struct exynos5_subcmu_info *exynos5800_subcmus[] = {
+       &exynos5x_disp_subcmu,
+       &exynos5x_gsc_subcmu,
+       &exynos5x_mfc_subcmu,
+       &exynos5x_mscl_subcmu,
+       &exynos5800_mau_subcmu,
 };
 
 static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = {
@@ -1539,11 +1593,17 @@ static void __init exynos5x_clk_init(struct device_node *np,
        samsung_clk_extended_sleep_init(reg_base,
                exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
                exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
-       if (soc == EXYNOS5800)
+
+       if (soc == EXYNOS5800) {
                samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
                                       ARRAY_SIZE(exynos5800_clk_regs));
-       exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus),
-                            exynos5x_subcmus);
+
+               exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus),
+                                    exynos5800_subcmus);
+       } else {
+               exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus),
+                                    exynos5x_subcmus);
+       }
 
        samsung_clk_of_add_provider(np, ctx);
 }
index 5c50e72..1a191ee 100644 (file)
@@ -38,7 +38,7 @@ static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
        if (socfpgaclk->fixed_div) {
                div = socfpgaclk->fixed_div;
        } else {
-               if (!socfpgaclk->bypass_reg)
+               if (socfpgaclk->hw.reg)
                        div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
        }
 
index 09e0311..470c7ef 100644 (file)
@@ -2,6 +2,10 @@
 /*
  * Copyright (C) 2012 Regents of the University of California
  * Copyright (C) 2017 SiFive
+ *
+ * All RISC-V systems have a timer attached to every hart.  These timers can be
+ * read from the "time" and "timeh" CSRs, and can use the SBI to setup
+ * events.
  */
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <asm/smp.h>
 #include <asm/sbi.h>
 
-/*
- * All RISC-V systems have a timer attached to every hart.  These timers can be
- * read by the 'rdcycle' pseudo instruction, and can use the SBI to setup
- * events.  In order to abstract the architecture-specific timer reading and
- * setting functions away from the clock event insertion code, we provide
- * function pointers to the clockevent subsystem that perform two basic
- * operations: rdtime() reads the timer on the current CPU, and
- * next_event(delta) sets the next timer event to 'delta' cycles in the future.
- * As the timers are inherently a per-cpu resource, these callbacks perform
- * operations on the current hart.  There is guaranteed to be exactly one timer
- * per hart on all RISC-V systems.
- */
-
 static int riscv_clock_next_event(unsigned long delta,
                struct clock_event_device *ce)
 {
index 8dda623..c28ebf2 100644 (file)
@@ -2528,7 +2528,7 @@ static int cpufreq_boost_set_sw(int state)
                }
 
                ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
-               if (ret)
+               if (ret < 0)
                        break;
        }
 
index 48cb3d4..d853047 100644 (file)
@@ -13,6 +13,16 @@ config ARM_CPUIDLE
           initialized by calling the CPU operations init idle hook
           provided by architecture code.
 
+config ARM_PSCI_CPUIDLE
+       bool "PSCI CPU idle Driver"
+       depends on ARM_PSCI_FW
+       select DT_IDLE_STATES
+       select CPU_IDLE_MULTIPLE_DRIVERS
+       help
+         Select this to enable PSCI firmware based CPUidle driver for ARM.
+         It provides an idle driver that is capable of detecting and
+         managing idle states through the PSCI firmware interface.
+
 config ARM_BIG_LITTLE_CPUIDLE
        bool "Support for ARM big.LITTLE processors"
        depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS
index 9d7176c..40d0163 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
 obj-$(CONFIG_ARM_EXYNOS_CPUIDLE)        += cpuidle-exynos.o
 obj-$(CONFIG_ARM_CPUIDLE)              += cpuidle-arm.o
+obj-$(CONFIG_ARM_PSCI_CPUIDLE)         += cpuidle-psci.o
 
 ###############################################################################
 # MIPS drivers
index 5bcd82c..9e5156d 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/slab.h>
-#include <linux/topology.h>
 
 #include <asm/cpuidle.h>
 
@@ -106,11 +105,17 @@ static int __init arm_idle_init_cpu(int cpu)
        ret = arm_cpuidle_init(cpu);
 
        /*
-        * Allow the initialization to continue for other CPUs, if the reported
-        * failure is a HW misconfiguration/breakage (-ENXIO).
+        * Allow the initialization to continue for other CPUs, if the
+        * reported failure is a HW misconfiguration/breakage (-ENXIO).
+        *
+        * Some platforms do not support idle operations
+        * (arm_cpuidle_init() returning -EOPNOTSUPP), we should
+        * not flag this case as an error, it is a valid
+        * configuration.
         */
        if (ret) {
-               pr_err("CPU %d failed to init idle CPU ops\n", cpu);
+               if (ret != -EOPNOTSUPP)
+                       pr_err("CPU %d failed to init idle CPU ops\n", cpu);
                ret = ret == -ENXIO ? 0 : ret;
                goto out_kfree_drv;
        }
diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c
new file mode 100644 (file)
index 0000000..f3c1a23
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PSCI CPU idle driver.
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ */
+
+#define pr_fmt(fmt) "CPUidle PSCI: " fmt
+
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_pm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/psci.h>
+#include <linux/slab.h>
+
+#include <asm/cpuidle.h>
+
+#include "dt_idle_states.h"
+
+static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+
+static int psci_enter_idle_state(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int idx)
+{
+       u32 *state = __this_cpu_read(psci_power_state);
+
+       return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter,
+                                          idx, state[idx - 1]);
+}
+
+static struct cpuidle_driver psci_idle_driver __initdata = {
+       .name = "psci_idle",
+       .owner = THIS_MODULE,
+       /*
+        * PSCI idle states relies on architectural WFI to
+        * be represented as state index 0.
+        */
+       .states[0] = {
+               .enter                  = psci_enter_idle_state,
+               .exit_latency           = 1,
+               .target_residency       = 1,
+               .power_usage            = UINT_MAX,
+               .name                   = "WFI",
+               .desc                   = "ARM WFI",
+       }
+};
+
+static const struct of_device_id psci_idle_state_match[] __initconst = {
+       { .compatible = "arm,idle-state",
+         .data = psci_enter_idle_state },
+       { },
+};
+
+static int __init psci_dt_parse_state_node(struct device_node *np, u32 *state)
+{
+       int err = of_property_read_u32(np, "arm,psci-suspend-param", state);
+
+       if (err) {
+               pr_warn("%pOF missing arm,psci-suspend-param property\n", np);
+               return err;
+       }
+
+       if (!psci_power_state_is_valid(*state)) {
+               pr_warn("Invalid PSCI power state %#x\n", *state);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __init psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
+{
+       int i, ret = 0, count = 0;
+       u32 *psci_states;
+       struct device_node *state_node;
+
+       /* Count idle states */
+       while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
+                                             count))) {
+               count++;
+               of_node_put(state_node);
+       }
+
+       if (!count)
+               return -ENODEV;
+
+       psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
+       if (!psci_states)
+               return -ENOMEM;
+
+       for (i = 0; i < count; i++) {
+               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+               ret = psci_dt_parse_state_node(state_node, &psci_states[i]);
+               of_node_put(state_node);
+
+               if (ret)
+                       goto free_mem;
+
+               pr_debug("psci-power-state %#x index %d\n", psci_states[i], i);
+       }
+
+       /* Idle states parsed correctly, initialize per-cpu pointer */
+       per_cpu(psci_power_state, cpu) = psci_states;
+       return 0;
+
+free_mem:
+       kfree(psci_states);
+       return ret;
+}
+
+static __init int psci_cpu_init_idle(unsigned int cpu)
+{
+       struct device_node *cpu_node;
+       int ret;
+
+       /*
+        * If the PSCI cpu_suspend function hook has not been initialized
+        * idle states must not be enabled, so bail out
+        */
+       if (!psci_ops.cpu_suspend)
+               return -EOPNOTSUPP;
+
+       cpu_node = of_cpu_device_node_get(cpu);
+       if (!cpu_node)
+               return -ENODEV;
+
+       ret = psci_dt_cpu_init_idle(cpu_node, cpu);
+
+       of_node_put(cpu_node);
+
+       return ret;
+}
+
+static int __init psci_idle_init_cpu(int cpu)
+{
+       struct cpuidle_driver *drv;
+       struct device_node *cpu_node;
+       const char *enable_method;
+       int ret = 0;
+
+       cpu_node = of_cpu_device_node_get(cpu);
+       if (!cpu_node)
+               return -ENODEV;
+
+       /*
+        * Check whether the enable-method for the cpu is PSCI, fail
+        * if it is not.
+        */
+       enable_method = of_get_property(cpu_node, "enable-method", NULL);
+       if (!enable_method || (strcmp(enable_method, "psci")))
+               ret = -ENODEV;
+
+       of_node_put(cpu_node);
+       if (ret)
+               return ret;
+
+       drv = kmemdup(&psci_idle_driver, sizeof(*drv), GFP_KERNEL);
+       if (!drv)
+               return -ENOMEM;
+
+       drv->cpumask = (struct cpumask *)cpumask_of(cpu);
+
+       /*
+        * Initialize idle states data, starting at index 1, since
+        * by default idle state 0 is the quiescent state reached
+        * by the cpu by executing the wfi instruction.
+        *
+        * If no DT idle states are detected (ret == 0) let the driver
+        * initialization fail accordingly since there is no reason to
+        * initialize the idle driver if only wfi is supported, the
+        * default archictectural back-end already executes wfi
+        * on idle entry.
+        */
+       ret = dt_init_idle_driver(drv, psci_idle_state_match, 1);
+       if (ret <= 0) {
+               ret = ret ? : -ENODEV;
+               goto out_kfree_drv;
+       }
+
+       /*
+        * Initialize PSCI idle states.
+        */
+       ret = psci_cpu_init_idle(cpu);
+       if (ret) {
+               pr_err("CPU %d failed to PSCI idle\n", cpu);
+               goto out_kfree_drv;
+       }
+
+       ret = cpuidle_register(drv, NULL);
+       if (ret)
+               goto out_kfree_drv;
+
+       return 0;
+
+out_kfree_drv:
+       kfree(drv);
+       return ret;
+}
+
+/*
+ * psci_idle_init - Initializes PSCI cpuidle driver
+ *
+ * Initializes PSCI cpuidle driver for all CPUs, if any CPU fails
+ * to register cpuidle driver then rollback to cancel all CPUs
+ * registration.
+ */
+static int __init psci_idle_init(void)
+{
+       int cpu, ret;
+       struct cpuidle_driver *drv;
+       struct cpuidle_device *dev;
+
+       for_each_possible_cpu(cpu) {
+               ret = psci_idle_init_cpu(cpu);
+               if (ret)
+                       goto out_fail;
+       }
+
+       return 0;
+
+out_fail:
+       while (--cpu >= 0) {
+               dev = per_cpu(cpuidle_devices, cpu);
+               drv = cpuidle_get_cpu_driver(dev);
+               cpuidle_unregister(drv);
+               kfree(drv);
+       }
+
+       return ret;
+}
+device_initcall(psci_idle_init);
index f79eede..edefa66 100644 (file)
@@ -540,6 +540,10 @@ int ccp_dev_suspend(struct sp_device *sp, pm_message_t state)
        unsigned long flags;
        unsigned int i;
 
+       /* If there's no device there's nothing to do */
+       if (!ccp)
+               return 0;
+
        spin_lock_irqsave(&ccp->cmd_lock, flags);
 
        ccp->suspending = 1;
@@ -564,6 +568,10 @@ int ccp_dev_resume(struct sp_device *sp)
        unsigned long flags;
        unsigned int i;
 
+       /* If there's no device there's nothing to do */
+       if (!ccp)
+               return 0;
+
        spin_lock_irqsave(&ccp->cmd_lock, flags);
 
        ccp->suspending = 0;
index 7c511e3..413efef 100644 (file)
@@ -295,7 +295,7 @@ config INTEL_IOATDMA
 
 config INTEL_IOP_ADMA
        tristate "Intel IOP32x ADMA support"
-       depends on ARCH_IOP32X || COMPILE_TEST
+       depends on ARCH_IOP32X
        select DMA_ENGINE
        select ASYNC_TX_ENABLE_CHANNEL_SWITCH
        help
index 8101ff2..67100e4 100644 (file)
 #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
 #define BCM2835_DMA_CHAN_NAME_SIZE 8
 
+/**
+ * struct bcm2835_dmadev - BCM2835 DMA controller
+ * @ddev: DMA device
+ * @base: base address of register map
+ * @dma_parms: DMA parameters (to convey 1 GByte max segment size to clients)
+ * @zero_page: bus address of zero page (to detect transactions copying from
+ *     zero page and avoid accessing memory if so)
+ */
 struct bcm2835_dmadev {
        struct dma_device ddev;
        void __iomem *base;
        struct device_dma_parameters dma_parms;
+       dma_addr_t zero_page;
 };
 
 struct bcm2835_dma_cb {
@@ -687,11 +696,12 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
        size_t period_len, enum dma_transfer_direction direction,
        unsigned long flags)
 {
+       struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device);
        struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
        struct bcm2835_desc *d;
        dma_addr_t src, dst;
        u32 info = BCM2835_DMA_WAIT_RESP;
-       u32 extra = BCM2835_DMA_INT_EN;
+       u32 extra = 0;
        size_t max_len = bcm2835_dma_max_frame_length(c);
        size_t frames;
 
@@ -707,6 +717,11 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
                return NULL;
        }
 
+       if (flags & DMA_PREP_INTERRUPT)
+               extra |= BCM2835_DMA_INT_EN;
+       else
+               period_len = buf_len;
+
        /*
         * warn if buf_len is not a multiple of period_len - this may leed
         * to unexpected latencies for interrupts and thus audiable clicks
@@ -732,6 +747,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
                dst = c->cfg.dst_addr;
                src = buf_addr;
                info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
+
+               /* non-lite channels can write zeroes w/o accessing memory */
+               if (buf_addr == od->zero_page && !c->is_lite_channel)
+                       info |= BCM2835_DMA_S_IGNORE;
        }
 
        /* calculate number of frames */
@@ -778,7 +797,10 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
 
        /* stop DMA activity */
        if (c->desc) {
-               vchan_terminate_vdesc(&c->desc->vd);
+               if (c->desc->vd.tx.flags & DMA_PREP_INTERRUPT)
+                       vchan_terminate_vdesc(&c->desc->vd);
+               else
+                       vchan_vdesc_fini(&c->desc->vd);
                c->desc = NULL;
                bcm2835_dma_abort(c);
        }
@@ -831,6 +853,9 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
                list_del(&c->vc.chan.device_node);
                tasklet_kill(&c->vc.task);
        }
+
+       dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE,
+                            DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
 }
 
 static const struct of_device_id bcm2835_dma_of_match[] = {
@@ -907,11 +932,20 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
        od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
                              BIT(DMA_MEM_TO_MEM);
        od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+       od->ddev.descriptor_reuse = true;
        od->ddev.dev = &pdev->dev;
        INIT_LIST_HEAD(&od->ddev.channels);
 
        platform_set_drvdata(pdev, od);
 
+       od->zero_page = dma_map_page_attrs(od->ddev.dev, ZERO_PAGE(0), 0,
+                                          PAGE_SIZE, DMA_TO_DEVICE,
+                                          DMA_ATTR_SKIP_CPU_SYNC);
+       if (dma_mapping_error(od->ddev.dev, od->zero_page)) {
+               dev_err(&pdev->dev, "Failed to map zero page\n");
+               return -ENOMEM;
+       }
+
        /* Request DMA channel mask from device tree */
        if (of_property_read_u32(pdev->dev.of_node,
                        "brcm,dma-channel-mask",
index b6cc90c..4e5f9f6 100644 (file)
@@ -50,7 +50,7 @@ struct dw_edma_burst {
 
 struct dw_edma_region {
        phys_addr_t                     paddr;
-       dma_addr_t                      vaddr;
+       void                            __iomem *vaddr;
        size_t                          sz;
 };
 
index 4c96e1c..dc85f55 100644 (file)
@@ -130,19 +130,19 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
        chip->id = pdev->devfn;
        chip->irq = pdev->irq;
 
-       dw->rg_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->rg_bar];
+       dw->rg_region.vaddr = pcim_iomap_table(pdev)[pdata->rg_bar];
        dw->rg_region.vaddr += pdata->rg_off;
        dw->rg_region.paddr = pdev->resource[pdata->rg_bar].start;
        dw->rg_region.paddr += pdata->rg_off;
        dw->rg_region.sz = pdata->rg_sz;
 
-       dw->ll_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->ll_bar];
+       dw->ll_region.vaddr = pcim_iomap_table(pdev)[pdata->ll_bar];
        dw->ll_region.vaddr += pdata->ll_off;
        dw->ll_region.paddr = pdev->resource[pdata->ll_bar].start;
        dw->ll_region.paddr += pdata->ll_off;
        dw->ll_region.sz = pdata->ll_sz;
 
-       dw->dt_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->dt_bar];
+       dw->dt_region.vaddr = pcim_iomap_table(pdev)[pdata->dt_bar];
        dw->dt_region.vaddr += pdata->dt_off;
        dw->dt_region.paddr = pdev->resource[pdata->dt_bar].start;
        dw->dt_region.paddr += pdata->dt_off;
@@ -158,17 +158,17 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
        pci_dbg(pdev, "Mode:\t%s\n",
                dw->mode == EDMA_MODE_LEGACY ? "Legacy" : "Unroll");
 
-       pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+       pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
                pdata->rg_bar, pdata->rg_off, pdata->rg_sz,
-               &dw->rg_region.vaddr, &dw->rg_region.paddr);
+               dw->rg_region.vaddr, &dw->rg_region.paddr);
 
-       pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+       pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
                pdata->ll_bar, pdata->ll_off, pdata->ll_sz,
-               &dw->ll_region.vaddr, &dw->ll_region.paddr);
+               dw->ll_region.vaddr, &dw->ll_region.paddr);
 
-       pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+       pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
                pdata->dt_bar, pdata->dt_off, pdata->dt_sz,
-               &dw->dt_region.vaddr, &dw->dt_region.paddr);
+               dw->dt_region.vaddr, &dw->dt_region.paddr);
 
        pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
 
index 8a3180e..692de47 100644 (file)
@@ -25,7 +25,7 @@ enum dw_edma_control {
 
 static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 {
-       return (struct dw_edma_v0_regs __iomem *)dw->rg_region.vaddr;
+       return dw->rg_region.vaddr;
 }
 
 #define SET(dw, name, value)                           \
@@ -192,13 +192,12 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
 static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 {
        struct dw_edma_burst *child;
-       struct dw_edma_v0_lli *lli;
-       struct dw_edma_v0_llp *llp;
+       struct dw_edma_v0_lli __iomem *lli;
+       struct dw_edma_v0_llp __iomem *llp;
        u32 control = 0, i = 0;
-       u64 sar, dar, addr;
        int j;
 
-       lli = (struct dw_edma_v0_lli *)chunk->ll_region.vaddr;
+       lli = chunk->ll_region.vaddr;
 
        if (chunk->cb)
                control = DW_EDMA_V0_CB;
@@ -214,17 +213,15 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
                /* Transfer size */
                SET_LL(&lli[i].transfer_size, child->sz);
                /* SAR - low, high */
-               sar = cpu_to_le64(child->sar);
-               SET_LL(&lli[i].sar_low, lower_32_bits(sar));
-               SET_LL(&lli[i].sar_high, upper_32_bits(sar));
+               SET_LL(&lli[i].sar_low, lower_32_bits(child->sar));
+               SET_LL(&lli[i].sar_high, upper_32_bits(child->sar));
                /* DAR - low, high */
-               dar = cpu_to_le64(child->dar);
-               SET_LL(&lli[i].dar_low, lower_32_bits(dar));
-               SET_LL(&lli[i].dar_high, upper_32_bits(dar));
+               SET_LL(&lli[i].dar_low, lower_32_bits(child->dar));
+               SET_LL(&lli[i].dar_high, upper_32_bits(child->dar));
                i++;
        }
 
-       llp = (struct dw_edma_v0_llp *)&lli[i];
+       llp = (void __iomem *)&lli[i];
        control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
        if (!chunk->cb)
                control |= DW_EDMA_V0_CB;
@@ -232,9 +229,8 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
        /* Channel control */
        SET_LL(&llp->control, control);
        /* Linked list  - low, high */
-       addr = cpu_to_le64(chunk->ll_region.paddr);
-       SET_LL(&llp->llp_low, lower_32_bits(addr));
-       SET_LL(&llp->llp_high, upper_32_bits(addr));
+       SET_LL(&llp->llp_low, lower_32_bits(chunk->ll_region.paddr));
+       SET_LL(&llp->llp_high, upper_32_bits(chunk->ll_region.paddr));
 }
 
 void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -242,7 +238,6 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
        struct dw_edma_chan *chan = chunk->chan;
        struct dw_edma *dw = chan->chip->dw;
        u32 tmp;
-       u64 llp;
 
        dw_edma_v0_core_write_chunk(chunk);
 
@@ -262,9 +257,10 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
                SET_CH(dw, chan->dir, chan->id, ch_control1,
                       (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
                /* Linked list - low, high */
-               llp = cpu_to_le64(chunk->ll_region.paddr);
-               SET_CH(dw, chan->dir, chan->id, llp_low, lower_32_bits(llp));
-               SET_CH(dw, chan->dir, chan->id, llp_high, upper_32_bits(llp));
+               SET_CH(dw, chan->dir, chan->id, llp_low,
+                      lower_32_bits(chunk->ll_region.paddr));
+               SET_CH(dw, chan->dir, chan->id, llp_high,
+                      upper_32_bits(chunk->ll_region.paddr));
        }
        /* Doorbell */
        SET_RW(dw, chan->dir, doorbell,
index 3226f52..4273950 100644 (file)
@@ -14,7 +14,7 @@
 #include "dw-edma-core.h"
 
 #define REGS_ADDR(name) \
-       ((dma_addr_t *)&regs->name)
+       ((void __force *)&regs->name)
 #define REGISTER(name) \
        { #name, REGS_ADDR(name) }
 
 
 static struct dentry                           *base_dir;
 static struct dw_edma                          *dw;
-static struct dw_edma_v0_regs                  *regs;
+static struct dw_edma_v0_regs                  __iomem *regs;
 
 static struct {
-       void                                    *start;
-       void                                    *end;
+       void                                    __iomem *start;
+       void                                    __iomem *end;
 } lim[2][EDMA_V0_MAX_NR_CH];
 
 struct debugfs_entries {
-       char                                    name[24];
+       const char                              *name;
        dma_addr_t                              *reg;
 };
 
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 {
+       void __iomem *reg = (void __force __iomem *)data;
        if (dw->mode == EDMA_MODE_LEGACY &&
-           data >= (void *)&regs->type.legacy.ch) {
-               void *ptr = (void *)&regs->type.legacy.ch;
+           reg >= (void __iomem *)&regs->type.legacy.ch) {
+               void __iomem *ptr = &regs->type.legacy.ch;
                u32 viewport_sel = 0;
                unsigned long flags;
                u16 ch;
 
                for (ch = 0; ch < dw->wr_ch_cnt; ch++)
-                       if (lim[0][ch].start >= data && data < lim[0][ch].end) {
-                               ptr += (data - lim[0][ch].start);
+                       if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
+                               ptr += (reg - lim[0][ch].start);
                                goto legacy_sel_wr;
                        }
 
                for (ch = 0; ch < dw->rd_ch_cnt; ch++)
-                       if (lim[1][ch].start >= data && data < lim[1][ch].end) {
-                               ptr += (data - lim[1][ch].start);
+                       if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
+                               ptr += (reg - lim[1][ch].start);
                                goto legacy_sel_rd;
                        }
 
@@ -86,7 +87,7 @@ legacy_sel_wr:
 
                raw_spin_unlock_irqrestore(&dw->lock, flags);
        } else {
-               *val = readl(data);
+               *val = readl(reg);
        }
 
        return 0;
@@ -105,7 +106,7 @@ static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
        }
 }
 
-static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs *regs,
+static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
                                    struct dentry *dir)
 {
        int nr_entries;
@@ -288,7 +289,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
        if (!dw)
                return;
 
-       regs = (struct dw_edma_v0_regs *)dw->rg_region.vaddr;
+       regs = dw->rg_region.vaddr;
        if (!regs)
                return;
 
index 23e0a35..ad72b3f 100644 (file)
@@ -1163,6 +1163,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
        switch (chan->feature & FSL_DMA_IP_MASK) {
        case FSL_DMA_IP_85XX:
                chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
+               /* Fall through */
        case FSL_DMA_IP_83XX:
                chan->toggle_ext_start = fsl_chan_toggle_ext_start;
                chan->set_src_loop_size = fsl_chan_set_src_loop_size;
index 9c41a4e..1072c45 100644 (file)
@@ -192,6 +192,7 @@ struct rcar_dmac_chan {
  * @iomem: remapped I/O memory base
  * @n_channels: number of available channels
  * @channels: array of DMAC channels
+ * @channels_mask: bitfield of which DMA channels are managed by this driver
  * @modules: bitmask of client modules in use
  */
 struct rcar_dmac {
@@ -202,6 +203,7 @@ struct rcar_dmac {
 
        unsigned int n_channels;
        struct rcar_dmac_chan *channels;
+       unsigned int channels_mask;
 
        DECLARE_BITMAP(modules, 256);
 };
@@ -438,7 +440,7 @@ static int rcar_dmac_init(struct rcar_dmac *dmac)
        u16 dmaor;
 
        /* Clear all channels and enable the DMAC globally. */
-       rcar_dmac_write(dmac, RCAR_DMACHCLR, GENMASK(dmac->n_channels - 1, 0));
+       rcar_dmac_write(dmac, RCAR_DMACHCLR, dmac->channels_mask);
        rcar_dmac_write(dmac, RCAR_DMAOR,
                        RCAR_DMAOR_PRI_FIXED | RCAR_DMAOR_DME);
 
@@ -814,6 +816,9 @@ static void rcar_dmac_stop_all_chan(struct rcar_dmac *dmac)
        for (i = 0; i < dmac->n_channels; ++i) {
                struct rcar_dmac_chan *chan = &dmac->channels[i];
 
+               if (!(dmac->channels_mask & BIT(i)))
+                       continue;
+
                /* Stop and reinitialize the channel. */
                spin_lock_irq(&chan->lock);
                rcar_dmac_chan_halt(chan);
@@ -1776,6 +1781,8 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
        return 0;
 }
 
+#define RCAR_DMAC_MAX_CHANNELS 32
+
 static int rcar_dmac_parse_of(struct device *dev, struct rcar_dmac *dmac)
 {
        struct device_node *np = dev->of_node;
@@ -1787,12 +1794,16 @@ static int rcar_dmac_parse_of(struct device *dev, struct rcar_dmac *dmac)
                return ret;
        }
 
-       if (dmac->n_channels <= 0 || dmac->n_channels >= 100) {
+       /* The hardware and driver don't support more than 32 bits in CHCLR */
+       if (dmac->n_channels <= 0 ||
+           dmac->n_channels >= RCAR_DMAC_MAX_CHANNELS) {
                dev_err(dev, "invalid number of channels %u\n",
                        dmac->n_channels);
                return -EINVAL;
        }
 
+       dmac->channels_mask = GENMASK(dmac->n_channels - 1, 0);
+
        return 0;
 }
 
@@ -1802,7 +1813,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
                DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES |
                DMA_SLAVE_BUSWIDTH_8_BYTES | DMA_SLAVE_BUSWIDTH_16_BYTES |
                DMA_SLAVE_BUSWIDTH_32_BYTES | DMA_SLAVE_BUSWIDTH_64_BYTES;
-       unsigned int channels_offset = 0;
        struct dma_device *engine;
        struct rcar_dmac *dmac;
        struct resource *mem;
@@ -1831,10 +1841,8 @@ static int rcar_dmac_probe(struct platform_device *pdev)
         * level we can't disable it selectively, so ignore channel 0 for now if
         * the device is part of an IOMMU group.
         */
-       if (device_iommu_mapped(&pdev->dev)) {
-               dmac->n_channels--;
-               channels_offset = 1;
-       }
+       if (device_iommu_mapped(&pdev->dev))
+               dmac->channels_mask &= ~BIT(0);
 
        dmac->channels = devm_kcalloc(&pdev->dev, dmac->n_channels,
                                      sizeof(*dmac->channels), GFP_KERNEL);
@@ -1892,8 +1900,10 @@ static int rcar_dmac_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&engine->channels);
 
        for (i = 0; i < dmac->n_channels; ++i) {
-               ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i],
-                                          i + channels_offset);
+               if (!(dmac->channels_mask & BIT(i)))
+                       continue;
+
+               ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i], i);
                if (ret < 0)
                        goto error;
        }
index baac476..525dc73 100644 (file)
@@ -908,6 +908,7 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
        struct dma_slave_config *slave_cfg = &schan->slave_cfg;
        dma_addr_t src = 0, dst = 0;
+       dma_addr_t start_src = 0, start_dst = 0;
        struct sprd_dma_desc *sdesc;
        struct scatterlist *sg;
        u32 len = 0;
@@ -954,6 +955,11 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        dst = sg_dma_address(sg);
                }
 
+               if (!i) {
+                       start_src = src;
+                       start_dst = dst;
+               }
+
                /*
                 * The link-list mode needs at least 2 link-list
                 * configurations. If there is only one sg, it doesn't
@@ -970,8 +976,8 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                }
        }
 
-       ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, src, dst, len,
-                                dir, flags, slave_cfg);
+       ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, start_src,
+                                start_dst, len, dir, flags, slave_cfg);
        if (ret) {
                kfree(sdesc);
                return NULL;
index 89d7108..de8bfd9 100644 (file)
@@ -142,7 +142,7 @@ enum d40_events {
  * when the DMA hw is powered off.
  * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works.
  */
-static u32 d40_backup_regs[] = {
+static __maybe_unused u32 d40_backup_regs[] = {
        D40_DREG_LCPA,
        D40_DREG_LCLA,
        D40_DREG_PRMSE,
@@ -211,7 +211,7 @@ static u32 d40_backup_regs_v4b[] = {
 
 #define BACKUP_REGS_SZ_V4B ARRAY_SIZE(d40_backup_regs_v4b)
 
-static u32 d40_backup_regs_chan[] = {
+static __maybe_unused u32 d40_backup_regs_chan[] = {
        D40_CHAN_REG_SSCFG,
        D40_CHAN_REG_SSELT,
        D40_CHAN_REG_SSPTR,
index d6e919d..1311de7 100644 (file)
@@ -1366,7 +1366,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
 
        chan = &dmadev->chan[id];
        if (!chan) {
-               dev_err(chan2dev(chan), "MDMA channel not initialized\n");
+               dev_dbg(mdma2dev(dmadev), "MDMA channel not initialized\n");
                goto exit;
        }
 
index 2805853..b33cf6e 100644 (file)
@@ -712,7 +712,7 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
        return chan;
 }
 
-static int tegra_adma_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev)
 {
        struct tegra_adma *tdma = dev_get_drvdata(dev);
        struct tegra_adma_chan_regs *ch_reg;
@@ -744,7 +744,7 @@ clk_disable:
        return 0;
 }
 
-static int tegra_adma_runtime_resume(struct device *dev)
+static int __maybe_unused tegra_adma_runtime_resume(struct device *dev)
 {
        struct tegra_adma *tdma = dev_get_drvdata(dev);
        struct tegra_adma_chan_regs *ch_reg;
index ad2f0a4..f255056 100644 (file)
@@ -391,8 +391,10 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev)
 
                ret = of_property_read_u32_array(node, pname, (u32 *)rsv_events,
                                                 nelm * 2);
-               if (ret)
+               if (ret) {
+                       kfree(rsv_events);
                        return ret;
+               }
 
                for (i = 0; i < nelm; i++) {
                        ti_dra7_xbar_reserve(rsv_events[i][0], rsv_events[i][1],
index ba2489d..d07c0d5 100644 (file)
@@ -1234,7 +1234,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_interleaved(
        if (src_icg) {
                d->ccr |= CCR_SRC_AMODE_DBLIDX;
                d->ei = 1;
-               d->fi = src_icg;
+               d->fi = src_icg + 1;
        } else if (xt->src_inc) {
                d->ccr |= CCR_SRC_AMODE_POSTINC;
                d->fi = 0;
@@ -1249,7 +1249,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_interleaved(
        if (dst_icg) {
                d->ccr |= CCR_DST_AMODE_DBLIDX;
                sg->ei = 1;
-               sg->fi = dst_icg;
+               sg->fi = dst_icg + 1;
        } else if (xt->dst_inc) {
                d->ccr |= CCR_DST_AMODE_POSTINC;
                sg->fi = 0;
@@ -1540,8 +1540,10 @@ static int omap_dma_probe(struct platform_device *pdev)
 
                rc = devm_request_irq(&pdev->dev, irq, omap_dma_irq,
                                      IRQF_SHARED, "omap-dma-engine", od);
-               if (rc)
+               if (rc) {
+                       omap_dma_free(od);
                        return rc;
+               }
        }
 
        if (omap_dma_glbl_read(od, CAPS_0) & CAPS_0_SUPPORT_LL123)
index 200c04c..2a2603b 100644 (file)
@@ -510,4 +510,11 @@ config EDAC_ASPEED
          First, ECC must be configured in the bootloader. Then, this driver
          will expose error counters via the EDAC kernel framework.
 
+config EDAC_BLUEFIELD
+       tristate "Mellanox BlueField Memory ECC"
+       depends on ARM64 && ((MELLANOX_PLATFORM && ACPI) || COMPILE_TEST)
+       help
+         Support for error detection and correction on the
+         Mellanox BlueField SoCs.
+
 endif # EDAC
index 165ca65..d265ff9 100644 (file)
@@ -85,3 +85,4 @@ obj-$(CONFIG_EDAC_XGENE)              += xgene_edac.o
 obj-$(CONFIG_EDAC_TI)                  += ti_edac.o
 obj-$(CONFIG_EDAC_QCOM)                        += qcom_edac.o
 obj-$(CONFIG_EDAC_ASPEED)              += aspeed_edac.o
+obj-$(CONFIG_EDAC_BLUEFIELD)           += bluefield_edac.o
index c2e693e..fbda4b8 100644 (file)
@@ -222,7 +222,6 @@ static unsigned long get_total_mem(void)
 static const struct of_device_id altr_sdram_ctrl_of_match[] = {
        { .compatible = "altr,sdram-edac", .data = &c5_data},
        { .compatible = "altr,sdram-edac-a10", .data = &a10_data},
-       { .compatible = "altr,sdram-edac-s10", .data = &a10_data},
        {},
 };
 MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
@@ -1170,6 +1169,24 @@ static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat)
        return 0;
 }
 
+/*********************** SDRAM EDAC Device Functions *********************/
+
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+
+static const struct edac_device_prv_data s10_sdramecc_data = {
+       .setup = altr_check_ecc_deps,
+       .ce_clear_mask = ALTR_S10_ECC_SERRPENA,
+       .ue_clear_mask = ALTR_S10_ECC_DERRPENA,
+       .ecc_enable_mask = ALTR_S10_ECC_EN,
+       .ecc_en_ofst = ALTR_S10_ECC_CTRL_SDRAM_OFST,
+       .ce_set_mask = ALTR_S10_ECC_TSERRA,
+       .ue_set_mask = ALTR_S10_ECC_TDERRA,
+       .set_err_ofst = ALTR_S10_ECC_INTTEST_OFST,
+       .ecc_irq_handler = altr_edac_a10_ecc_irq,
+       .inject_fops = &altr_edac_a10_device_inject_fops,
+};
+#endif /* CONFIG_EDAC_ALTERA_SDRAM */
+
 /*********************** OCRAM EDAC Device Functions *********************/
 
 #ifdef CONFIG_EDAC_ALTERA_OCRAM
@@ -1758,6 +1775,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = {
 #endif
 #ifdef CONFIG_EDAC_ALTERA_SDMMC
        { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data },
+#endif
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+       { .compatible = "altr,sdram-edac-s10", .data = &s10_sdramecc_data },
 #endif
        {},
 };
@@ -1866,6 +1886,7 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc)
        struct altr_arria10_edac *edac = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        int irq = irq_desc_get_irq(desc);
+       unsigned long bits;
 
        dberr = (irq == edac->db_irq) ? 1 : 0;
        sm_offset = dberr ? A10_SYSMGR_ECC_INTSTAT_DERR_OFST :
@@ -1875,7 +1896,8 @@ static void altr_edac_a10_irq_handler(struct irq_desc *desc)
 
        regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status);
 
-       for_each_set_bit(bit, (unsigned long *)&irq_status, 32) {
+       bits = irq_status;
+       for_each_set_bit(bit, &bits, 32) {
                irq = irq_linear_revmap(edac->domain, dberr * 32 + bit);
                if (irq)
                        generic_handle_irq(irq);
@@ -1889,6 +1911,10 @@ static int validate_parent_available(struct device_node *np)
        struct device_node *parent;
        int ret = 0;
 
+       /* SDRAM must be present for Linux (implied parent) */
+       if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
+               return 0;
+
        /* Ensure parent device is enabled if parent node exists */
        parent = of_parse_phandle(np, "altr,ecc-parent", 0);
        if (parent && !of_device_is_available(parent))
@@ -1898,6 +1924,22 @@ static int validate_parent_available(struct device_node *np)
        return ret;
 }
 
+static int get_s10_sdram_edac_resource(struct device_node *np,
+                                      struct resource *res)
+{
+       struct device_node *parent;
+       int ret;
+
+       parent = of_parse_phandle(np, "altr,sdr-syscon", 0);
+       if (!parent)
+               return -ENODEV;
+
+       ret = of_address_to_resource(parent, 0, res);
+       of_node_put(parent);
+
+       return ret;
+}
+
 static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
                                    struct device_node *np)
 {
@@ -1925,7 +1967,11 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
        if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
                return -ENOMEM;
 
-       rc = of_address_to_resource(np, 0, &res);
+       if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
+               rc = get_s10_sdram_edac_resource(np, &res);
+       else
+               rc = of_address_to_resource(np, 0, &res);
+
        if (rc < 0) {
                edac_printk(KERN_ERR, EDAC_DEVICE,
                            "%s: no resource address\n", ecc_name);
@@ -2231,13 +2277,15 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
                    of_device_is_compatible(child, "altr,socfpga-dma-ecc") ||
                    of_device_is_compatible(child, "altr,socfpga-usb-ecc") ||
                    of_device_is_compatible(child, "altr,socfpga-qspi-ecc") ||
+#ifdef CONFIG_EDAC_ALTERA_SDRAM
+                   of_device_is_compatible(child, "altr,sdram-edac-s10") ||
+#endif
                    of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc"))
 
                        altr_edac_a10_device_add(edac, child);
 
 #ifdef CONFIG_EDAC_ALTERA_SDRAM
-               else if ((of_device_is_compatible(child, "altr,sdram-edac-a10")) ||
-                        (of_device_is_compatible(child, "altr,sdram-edac-s10")))
+               else if (of_device_is_compatible(child, "altr,sdram-edac-a10"))
                        of_platform_populate(pdev->dev.of_node,
                                             altr_sdram_ctrl_of_match,
                                             NULL, &pdev->dev);
index 55654cc..3727e72 100644 (file)
@@ -289,6 +289,29 @@ struct altr_sdram_mc_data {
 #define ALTR_A10_ECC_INIT_WATCHDOG_10US      10000
 
 /************* Stratix10 Defines **************/
+#define ALTR_S10_ECC_CTRL_SDRAM_OFST      0x00
+#define ALTR_S10_ECC_EN                   BIT(0)
+
+#define ALTR_S10_ECC_ERRINTEN_OFST        0x10
+#define ALTR_S10_ECC_ERRINTENS_OFST       0x14
+#define ALTR_S10_ECC_ERRINTENR_OFST       0x18
+#define ALTR_S10_ECC_SERRINTEN            BIT(0)
+
+#define ALTR_S10_ECC_INTMODE_OFST         0x1C
+#define ALTR_S10_ECC_INTMODE              BIT(0)
+
+#define ALTR_S10_ECC_INTSTAT_OFST         0x20
+#define ALTR_S10_ECC_SERRPENA             BIT(0)
+#define ALTR_S10_ECC_DERRPENA             BIT(8)
+#define ALTR_S10_ECC_ERRPENA_MASK         (ALTR_S10_ECC_SERRPENA | \
+                                          ALTR_S10_ECC_DERRPENA)
+
+#define ALTR_S10_ECC_INTTEST_OFST         0x24
+#define ALTR_S10_ECC_TSERRA               BIT(0)
+#define ALTR_S10_ECC_TDERRA               BIT(8)
+#define ALTR_S10_ECC_TSERRB               BIT(16)
+#define ALTR_S10_ECC_TDERRB               BIT(24)
+
 #define ALTR_S10_DERR_ADDRA_OFST          0x2C
 
 /* Stratix10 ECC Manager Defines */
@@ -300,7 +323,7 @@ struct altr_sdram_mc_data {
 #define S10_SYSMGR_UE_ADDR_OFST           0x224
 
 #define S10_DDR0_IRQ_MASK                 BIT(16)
-#define S10_DBE_IRQ_MASK                  0x3FE
+#define S10_DBE_IRQ_MASK                  0x3FFFE
 
 /* Define ECC Block Offsets for peripherals */
 #define ECC_BLK_ADDRESS_OFST              0x40
index 873437b..c1d4536 100644 (file)
@@ -788,51 +788,45 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
                 (dclr & BIT(15)) ?  "yes" : "no");
 }
 
-/*
- * The Address Mask should be a contiguous set of bits in the non-interleaved
- * case. So to check for CS interleaving, find the most- and least-significant
- * bits of the mask, generate a contiguous bitmask, and compare the two.
- */
-static bool f17_cs_interleaved(struct amd64_pvt *pvt, u8 ctrl, int cs)
+#define CS_EVEN_PRIMARY                BIT(0)
+#define CS_ODD_PRIMARY         BIT(1)
+#define CS_EVEN_SECONDARY      BIT(2)
+#define CS_ODD_SECONDARY       BIT(3)
+
+#define CS_EVEN                        (CS_EVEN_PRIMARY | CS_EVEN_SECONDARY)
+#define CS_ODD                 (CS_ODD_PRIMARY | CS_ODD_SECONDARY)
+
+static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
 {
-       u32 mask = pvt->csels[ctrl].csmasks[cs >> 1];
-       u32 msb = fls(mask) - 1, lsb = ffs(mask) - 1;
-       u32 test_mask = GENMASK(msb, lsb);
+       int cs_mode = 0;
 
-       edac_dbg(1, "mask=0x%08x test_mask=0x%08x\n", mask, test_mask);
+       if (csrow_enabled(2 * dimm, ctrl, pvt))
+               cs_mode |= CS_EVEN_PRIMARY;
 
-       return mask ^ test_mask;
+       if (csrow_enabled(2 * dimm + 1, ctrl, pvt))
+               cs_mode |= CS_ODD_PRIMARY;
+
+       /* Asymmetric dual-rank DIMM support. */
+       if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt))
+               cs_mode |= CS_ODD_SECONDARY;
+
+       return cs_mode;
 }
 
 static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
 {
-       int dimm, size0, size1, cs0, cs1;
+       int dimm, size0, size1, cs0, cs1, cs_mode;
 
        edac_printk(KERN_DEBUG, EDAC_MC, "UMC%d chip selects:\n", ctrl);
 
-       for (dimm = 0; dimm < 4; dimm++) {
-               size0 = 0;
+       for (dimm = 0; dimm < 2; dimm++) {
                cs0 = dimm * 2;
-
-               if (csrow_enabled(cs0, ctrl, pvt))
-                       size0 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs0);
-
-               size1 = 0;
                cs1 = dimm * 2 + 1;
 
-               if (csrow_enabled(cs1, ctrl, pvt)) {
-                       /*
-                        * CS interleaving is only supported if both CSes have
-                        * the same amount of memory. Because they are
-                        * interleaved, it will look like both CSes have the
-                        * full amount of memory. Save the size for both as
-                        * half the amount we found on CS0, if interleaved.
-                        */
-                       if (f17_cs_interleaved(pvt, ctrl, cs1))
-                               size1 = size0 = (size0 >> 1);
-                       else
-                               size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
-               }
+               cs_mode = f17_get_cs_mode(dimm, ctrl, pvt);
+
+               size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0);
+               size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1);
 
                amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
                                cs0,    size0,
@@ -942,89 +936,119 @@ static void prep_chip_selects(struct amd64_pvt *pvt)
        } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
                pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
                pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
+       } else if (pvt->fam >= 0x17) {
+               int umc;
+
+               for_each_umc(umc) {
+                       pvt->csels[umc].b_cnt = 4;
+                       pvt->csels[umc].m_cnt = 2;
+               }
+
        } else {
                pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
                pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
        }
 }
 
+static void read_umc_base_mask(struct amd64_pvt *pvt)
+{
+       u32 umc_base_reg, umc_base_reg_sec;
+       u32 umc_mask_reg, umc_mask_reg_sec;
+       u32 base_reg, base_reg_sec;
+       u32 mask_reg, mask_reg_sec;
+       u32 *base, *base_sec;
+       u32 *mask, *mask_sec;
+       int cs, umc;
+
+       for_each_umc(umc) {
+               umc_base_reg = get_umc_base(umc) + UMCCH_BASE_ADDR;
+               umc_base_reg_sec = get_umc_base(umc) + UMCCH_BASE_ADDR_SEC;
+
+               for_each_chip_select(cs, umc, pvt) {
+                       base = &pvt->csels[umc].csbases[cs];
+                       base_sec = &pvt->csels[umc].csbases_sec[cs];
+
+                       base_reg = umc_base_reg + (cs * 4);
+                       base_reg_sec = umc_base_reg_sec + (cs * 4);
+
+                       if (!amd_smn_read(pvt->mc_node_id, base_reg, base))
+                               edac_dbg(0, "  DCSB%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *base, base_reg);
+
+                       if (!amd_smn_read(pvt->mc_node_id, base_reg_sec, base_sec))
+                               edac_dbg(0, "    DCSB_SEC%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *base_sec, base_reg_sec);
+               }
+
+               umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK;
+               umc_mask_reg_sec = get_umc_base(umc) + UMCCH_ADDR_MASK_SEC;
+
+               for_each_chip_select_mask(cs, umc, pvt) {
+                       mask = &pvt->csels[umc].csmasks[cs];
+                       mask_sec = &pvt->csels[umc].csmasks_sec[cs];
+
+                       mask_reg = umc_mask_reg + (cs * 4);
+                       mask_reg_sec = umc_mask_reg_sec + (cs * 4);
+
+                       if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask))
+                               edac_dbg(0, "  DCSM%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *mask, mask_reg);
+
+                       if (!amd_smn_read(pvt->mc_node_id, mask_reg_sec, mask_sec))
+                               edac_dbg(0, "    DCSM_SEC%d[%d]=0x%08x reg: 0x%x\n",
+                                        umc, cs, *mask_sec, mask_reg_sec);
+               }
+       }
+}
+
 /*
  * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
  */
 static void read_dct_base_mask(struct amd64_pvt *pvt)
 {
-       int base_reg0, base_reg1, mask_reg0, mask_reg1, cs;
+       int cs;
 
        prep_chip_selects(pvt);
 
-       if (pvt->umc) {
-               base_reg0 = get_umc_base(0) + UMCCH_BASE_ADDR;
-               base_reg1 = get_umc_base(1) + UMCCH_BASE_ADDR;
-               mask_reg0 = get_umc_base(0) + UMCCH_ADDR_MASK;
-               mask_reg1 = get_umc_base(1) + UMCCH_ADDR_MASK;
-       } else {
-               base_reg0 = DCSB0;
-               base_reg1 = DCSB1;
-               mask_reg0 = DCSM0;
-               mask_reg1 = DCSM1;
-       }
+       if (pvt->umc)
+               return read_umc_base_mask(pvt);
 
        for_each_chip_select(cs, 0, pvt) {
-               int reg0   = base_reg0 + (cs * 4);
-               int reg1   = base_reg1 + (cs * 4);
+               int reg0   = DCSB0 + (cs * 4);
+               int reg1   = DCSB1 + (cs * 4);
                u32 *base0 = &pvt->csels[0].csbases[cs];
                u32 *base1 = &pvt->csels[1].csbases[cs];
 
-               if (pvt->umc) {
-                       if (!amd_smn_read(pvt->mc_node_id, reg0, base0))
-                               edac_dbg(0, "  DCSB0[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *base0, reg0);
+               if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
+                       edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base0, reg0);
 
-                       if (!amd_smn_read(pvt->mc_node_id, reg1, base1))
-                               edac_dbg(0, "  DCSB1[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *base1, reg1);
-               } else {
-                       if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, base0))
-                               edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *base0, reg0);
-
-                       if (pvt->fam == 0xf)
-                               continue;
+               if (pvt->fam == 0xf)
+                       continue;
 
-                       if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
-                               edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *base1, (pvt->fam == 0x10) ? reg1
-                                                               : reg0);
-               }
+               if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, base1))
+                       edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base1, (pvt->fam == 0x10) ? reg1
+                                                       : reg0);
        }
 
        for_each_chip_select_mask(cs, 0, pvt) {
-               int reg0   = mask_reg0 + (cs * 4);
-               int reg1   = mask_reg1 + (cs * 4);
+               int reg0   = DCSM0 + (cs * 4);
+               int reg1   = DCSM1 + (cs * 4);
                u32 *mask0 = &pvt->csels[0].csmasks[cs];
                u32 *mask1 = &pvt->csels[1].csmasks[cs];
 
-               if (pvt->umc) {
-                       if (!amd_smn_read(pvt->mc_node_id, reg0, mask0))
-                               edac_dbg(0, "    DCSM0[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *mask0, reg0);
-
-                       if (!amd_smn_read(pvt->mc_node_id, reg1, mask1))
-                               edac_dbg(0, "    DCSM1[%d]=0x%08x reg: 0x%x\n",
-                                        cs, *mask1, reg1);
-               } else {
-                       if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
-                               edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *mask0, reg0);
+               if (!amd64_read_dct_pci_cfg(pvt, 0, reg0, mask0))
+                       edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask0, reg0);
 
-                       if (pvt->fam == 0xf)
-                               continue;
+               if (pvt->fam == 0xf)
+                       continue;
 
-                       if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
-                               edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
-                                        cs, *mask1, (pvt->fam == 0x10) ? reg1
-                                                               : reg0);
-               }
+               if (!amd64_read_dct_pci_cfg(pvt, 1, reg0, mask1))
+                       edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask1, (pvt->fam == 0x10) ? reg1
+                                                       : reg0);
        }
 }
 
@@ -1556,18 +1580,58 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
                return ddr3_cs_size(cs_mode, false);
 }
 
-static int f17_base_addr_to_cs_size(struct amd64_pvt *pvt, u8 umc,
+static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
                                    unsigned int cs_mode, int csrow_nr)
 {
-       u32 base_addr = pvt->csels[umc].csbases[csrow_nr];
+       u32 addr_mask_orig, addr_mask_deinterleaved;
+       u32 msb, weight, num_zero_bits;
+       int dimm, size = 0;
 
-       /*  Each mask is used for every two base addresses. */
-       u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr >> 1];
+       /* No Chip Selects are enabled. */
+       if (!cs_mode)
+               return size;
 
-       /*  Register [31:1] = Address [39:9]. Size is in kBs here. */
-       u32 size = ((addr_mask >> 1) - (base_addr >> 1) + 1) >> 1;
+       /* Requested size of an even CS but none are enabled. */
+       if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1))
+               return size;
 
-       edac_dbg(1, "BaseAddr: 0x%x, AddrMask: 0x%x\n", base_addr, addr_mask);
+       /* Requested size of an odd CS but none are enabled. */
+       if (!(cs_mode & CS_ODD) && (csrow_nr & 1))
+               return size;
+
+       /*
+        * There is one mask per DIMM, and two Chip Selects per DIMM.
+        *      CS0 and CS1 -> DIMM0
+        *      CS2 and CS3 -> DIMM1
+        */
+       dimm = csrow_nr >> 1;
+
+       /* Asymmetric dual-rank DIMM support. */
+       if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY))
+               addr_mask_orig = pvt->csels[umc].csmasks_sec[dimm];
+       else
+               addr_mask_orig = pvt->csels[umc].csmasks[dimm];
+
+       /*
+        * The number of zero bits in the mask is equal to the number of bits
+        * in a full mask minus the number of bits in the current mask.
+        *
+        * The MSB is the number of bits in the full mask because BIT[0] is
+        * always 0.
+        */
+       msb = fls(addr_mask_orig) - 1;
+       weight = hweight_long(addr_mask_orig);
+       num_zero_bits = msb - weight;
+
+       /* Take the number of zero bits off from the top of the mask. */
+       addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1);
+
+       edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm);
+       edac_dbg(1, "  Original AddrMask: 0x%x\n", addr_mask_orig);
+       edac_dbg(1, "  Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved);
+
+       /* Register [31:1] = Address [39:9]. Size is in kBs here. */
+       size = (addr_mask_deinterleaved >> 2) + 1;
 
        /* Return size in MBs. */
        return size >> 10;
@@ -2232,7 +2296,7 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
        [F17_M10H_CPUS] = {
@@ -2241,7 +2305,7 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
        [F17_M30H_CPUS] = {
@@ -2250,7 +2314,16 @@ static struct amd64_family_type family_types[] = {
                .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
                .ops = {
                        .early_channel_count    = f17_early_channel_count,
-                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
+               }
+       },
+       [F17_M70H_CPUS] = {
+               .ctl_name = "F17h_M70h",
+               .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0,
+               .f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6,
+               .ops = {
+                       .early_channel_count    = f17_early_channel_count,
+                       .dbam_to_cs             = f17_addr_mask_to_cs_size,
                }
        },
 };
@@ -2537,13 +2610,6 @@ static void decode_umc_error(int node_id, struct mce *m)
 
        err.channel = find_umc_channel(m);
 
-       if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
-               err.err_code = ERR_NORM_ADDR;
-               goto log_error;
-       }
-
-       error_address_to_page_and_offset(sys_addr, &err);
-
        if (!(m->status & MCI_STATUS_SYNDV)) {
                err.err_code = ERR_SYND;
                goto log_error;
@@ -2560,6 +2626,13 @@ static void decode_umc_error(int node_id, struct mce *m)
 
        err.csrow = m->synd & 0x7;
 
+       if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
+               err.err_code = ERR_NORM_ADDR;
+               goto log_error;
+       }
+
+       error_address_to_page_and_offset(sys_addr, &err);
+
 log_error:
        __log_ecc_error(mci, &err, ecc_type);
 }
@@ -2809,10 +2882,12 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
        int csrow_nr = csrow_nr_orig;
        u32 cs_mode, nr_pages;
 
-       if (!pvt->umc)
+       if (!pvt->umc) {
                csrow_nr >>= 1;
-
-       cs_mode = DBAM_DIMM(csrow_nr, dbam);
+               cs_mode = DBAM_DIMM(csrow_nr, dbam);
+       } else {
+               cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt);
+       }
 
        nr_pages   = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr);
        nr_pages <<= 20 - PAGE_SHIFT;
@@ -2824,6 +2899,49 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig)
        return nr_pages;
 }
 
+static int init_csrows_df(struct mem_ctl_info *mci)
+{
+       struct amd64_pvt *pvt = mci->pvt_info;
+       enum edac_type edac_mode = EDAC_NONE;
+       enum dev_type dev_type = DEV_UNKNOWN;
+       struct dimm_info *dimm;
+       int empty = 1;
+       u8 umc, cs;
+
+       if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) {
+               edac_mode = EDAC_S16ECD16ED;
+               dev_type = DEV_X16;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_S8ECD8ED) {
+               edac_mode = EDAC_S8ECD8ED;
+               dev_type = DEV_X8;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED) {
+               edac_mode = EDAC_S4ECD4ED;
+               dev_type = DEV_X4;
+       } else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED) {
+               edac_mode = EDAC_SECDED;
+       }
+
+       for_each_umc(umc) {
+               for_each_chip_select(cs, umc, pvt) {
+                       if (!csrow_enabled(cs, umc, pvt))
+                               continue;
+
+                       empty = 0;
+                       dimm = mci->csrows[cs]->channels[umc]->dimm;
+
+                       edac_dbg(1, "MC node: %d, csrow: %d\n",
+                                       pvt->mc_node_id, cs);
+
+                       dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs);
+                       dimm->mtype = pvt->dram_type;
+                       dimm->edac_mode = edac_mode;
+                       dimm->dtype = dev_type;
+               }
+       }
+
+       return empty;
+}
+
 /*
  * Initialize the array of csrow attribute instances, based on the values
  * from pci config hardware registers.
@@ -2838,15 +2956,16 @@ static int init_csrows(struct mem_ctl_info *mci)
        int nr_pages = 0;
        u32 val;
 
-       if (!pvt->umc) {
-               amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
+       if (pvt->umc)
+               return init_csrows_df(mci);
 
-               pvt->nbcfg = val;
+       amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
 
-               edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
-                        pvt->mc_node_id, val,
-                        !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
-       }
+       pvt->nbcfg = val;
+
+       edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+                pvt->mc_node_id, val,
+                !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
        /*
         * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
@@ -2883,13 +3002,7 @@ static int init_csrows(struct mem_ctl_info *mci)
                edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
 
                /* Determine DIMM ECC mode: */
-               if (pvt->umc) {
-                       if (mci->edac_ctl_cap & EDAC_FLAG_S4ECD4ED)
-                               edac_mode = EDAC_S4ECD4ED;
-                       else if (mci->edac_ctl_cap & EDAC_FLAG_SECDED)
-                               edac_mode = EDAC_SECDED;
-
-               } else if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
+               if (pvt->nbcfg & NBCFG_ECC_ENABLE) {
                        edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL)
                                        ? EDAC_S4ECD4ED
                                        : EDAC_SECDED;
@@ -3137,12 +3250,15 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 static inline void
 f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
 {
-       u8 i, ecc_en = 1, cpk_en = 1;
+       u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1;
 
        for_each_umc(i) {
                if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
                        ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
                        cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
+
+                       dev_x4  &= !!(pvt->umc[i].dimm_cfg & BIT(6));
+                       dev_x16 &= !!(pvt->umc[i].dimm_cfg & BIT(7));
                }
        }
 
@@ -3150,8 +3266,15 @@ f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
        if (ecc_en) {
                mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
 
-               if (cpk_en)
+               if (!cpk_en)
+                       return;
+
+               if (dev_x4)
                        mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
+               else if (dev_x16)
+                       mci->edac_ctl_cap |= EDAC_FLAG_S16ECD16ED;
+               else
+                       mci->edac_ctl_cap |= EDAC_FLAG_S8ECD8ED;
        }
 }
 
@@ -3241,6 +3364,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                        fam_type = &family_types[F17_M30H_CPUS];
                        pvt->ops = &family_types[F17_M30H_CPUS].ops;
                        break;
+               } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) {
+                       fam_type = &family_types[F17_M70H_CPUS];
+                       pvt->ops = &family_types[F17_M70H_CPUS].ops;
+                       break;
                }
                /* fall through */
        case 0x18:
index 8f66472..8c3cda8 100644 (file)
@@ -96,6 +96,7 @@
 /* Hardware limit on ChipSelect rows per MC and processors per system */
 #define NUM_CHIPSELECTS                        8
 #define DRAM_RANGES                    8
+#define NUM_CONTROLLERS                        8
 
 #define ON true
 #define OFF false
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F6 0x1446
 
 /*
  * Function 1 - Address Map
 #define DCSM0                          0x60
 #define DCSM1                          0x160
 
-#define csrow_enabled(i, dct, pvt)     ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE)
+#define csrow_enabled(i, dct, pvt)     ((pvt)->csels[(dct)].csbases[(i)]     & DCSB_CS_ENABLE)
+#define csrow_sec_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases_sec[(i)] & DCSB_CS_ENABLE)
 
 #define DRAM_CONTROL                   0x78
 
 
 /* UMC CH register offsets */
 #define UMCCH_BASE_ADDR                        0x0
+#define UMCCH_BASE_ADDR_SEC            0x10
 #define UMCCH_ADDR_MASK                        0x20
+#define UMCCH_ADDR_MASK_SEC            0x28
 #define UMCCH_ADDR_CFG                 0x30
 #define UMCCH_DIMM_CFG                 0x80
 #define UMCCH_UMC_CFG                  0x100
@@ -285,6 +291,7 @@ enum amd_families {
        F17_CPUS,
        F17_M10H_CPUS,
        F17_M30H_CPUS,
+       F17_M70H_CPUS,
        NUM_FAMILIES,
 };
 
@@ -311,9 +318,11 @@ struct dram_range {
 /* A DCT chip selects collection */
 struct chip_select {
        u32 csbases[NUM_CHIPSELECTS];
+       u32 csbases_sec[NUM_CHIPSELECTS];
        u8 b_cnt;
 
        u32 csmasks[NUM_CHIPSELECTS];
+       u32 csmasks_sec[NUM_CHIPSELECTS];
        u8 m_cnt;
 };
 
@@ -351,8 +360,8 @@ struct amd64_pvt {
        u32 dbam0;              /* DRAM Base Address Mapping reg for DCT0 */
        u32 dbam1;              /* DRAM Base Address Mapping reg for DCT1 */
 
-       /* one for each DCT */
-       struct chip_select csels[2];
+       /* one for each DCT/UMC */
+       struct chip_select csels[NUM_CONTROLLERS];
 
        /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */
        struct dram_range ranges[DRAM_RANGES];
diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c
new file mode 100644 (file)
index 0000000..e4736eb
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Bluefield-specific EDAC driver.
+ *
+ * Copyright (c) 2019 Mellanox Technologies.
+ */
+
+#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
+#include <linux/bitfield.h>
+#include <linux/edac.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "edac_module.h"
+
+#define DRIVER_NAME            "bluefield-edac"
+
+/*
+ * Mellanox BlueField EMI (External Memory Interface) register definitions.
+ */
+
+#define MLXBF_ECC_CNT 0x340
+#define MLXBF_ECC_CNT__SERR_CNT GENMASK(15, 0)
+#define MLXBF_ECC_CNT__DERR_CNT GENMASK(31, 16)
+
+#define MLXBF_ECC_ERR 0x348
+#define MLXBF_ECC_ERR__SECC BIT(0)
+#define MLXBF_ECC_ERR__DECC BIT(16)
+
+#define MLXBF_ECC_LATCH_SEL 0x354
+#define MLXBF_ECC_LATCH_SEL__START BIT(24)
+
+#define MLXBF_ERR_ADDR_0 0x358
+
+#define MLXBF_ERR_ADDR_1 0x37c
+
+#define MLXBF_SYNDROM 0x35c
+#define MLXBF_SYNDROM__DERR BIT(0)
+#define MLXBF_SYNDROM__SERR BIT(1)
+#define MLXBF_SYNDROM__SYN GENMASK(25, 16)
+
+#define MLXBF_ADD_INFO 0x364
+#define MLXBF_ADD_INFO__ERR_PRANK GENMASK(9, 8)
+
+#define MLXBF_EDAC_MAX_DIMM_PER_MC     2
+#define MLXBF_EDAC_ERROR_GRAIN         8
+
+/*
+ * Request MLNX_SIP_GET_DIMM_INFO
+ *
+ * Retrieve information about DIMM on a certain slot.
+ *
+ * Call register usage:
+ * a0: MLNX_SIP_GET_DIMM_INFO
+ * a1: (Memory controller index) << 16 | (Dimm index in memory controller)
+ * a2-7: not used.
+ *
+ * Return status:
+ * a0: MLXBF_DIMM_INFO defined below describing the DIMM.
+ * a1-3: not used.
+ */
+#define MLNX_SIP_GET_DIMM_INFO         0x82000008
+
+/* Format for the SMC response about the memory information */
+#define MLXBF_DIMM_INFO__SIZE_GB GENMASK_ULL(15, 0)
+#define MLXBF_DIMM_INFO__IS_RDIMM BIT(16)
+#define MLXBF_DIMM_INFO__IS_LRDIMM BIT(17)
+#define MLXBF_DIMM_INFO__IS_NVDIMM BIT(18)
+#define MLXBF_DIMM_INFO__RANKS GENMASK_ULL(23, 21)
+#define MLXBF_DIMM_INFO__PACKAGE_X GENMASK_ULL(31, 24)
+
+struct bluefield_edac_priv {
+       int dimm_ranks[MLXBF_EDAC_MAX_DIMM_PER_MC];
+       void __iomem *emi_base;
+       int dimm_per_mc;
+};
+
+static u64 smc_call1(u64 smc_op, u64 smc_arg)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res);
+
+       return res.a0;
+}
+
+/*
+ * Gather the ECC information from the External Memory Interface registers
+ * and report it to the edac handler.
+ */
+static void bluefield_gather_report_ecc(struct mem_ctl_info *mci,
+                                       int error_cnt,
+                                       int is_single_ecc)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       u32 dram_additional_info, err_prank, edea0, edea1;
+       u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom;
+       enum hw_event_mc_err_type ecc_type;
+       u64 ecc_dimm_addr;
+       int ecc_dimm;
+
+       ecc_type = is_single_ecc ? HW_EVENT_ERR_CORRECTED :
+                                  HW_EVENT_ERR_UNCORRECTED;
+
+       /*
+        * Tell the External Memory Interface to populate the relevant
+        * registers with information about the last ECC error occurrence.
+        */
+       ecc_latch_select = MLXBF_ECC_LATCH_SEL__START;
+       writel(ecc_latch_select, priv->emi_base + MLXBF_ECC_LATCH_SEL);
+
+       /*
+        * Verify that the ECC reported info in the registers is of the
+        * same type as the one asked to report. If not, just report the
+        * error without the detailed information.
+        */
+       dram_syndrom = readl(priv->emi_base + MLXBF_SYNDROM);
+       serr = FIELD_GET(MLXBF_SYNDROM__SERR, dram_syndrom);
+       derr = FIELD_GET(MLXBF_SYNDROM__DERR, dram_syndrom);
+       syndrom = FIELD_GET(MLXBF_SYNDROM__SYN, dram_syndrom);
+
+       if ((is_single_ecc && !serr) || (!is_single_ecc && !derr)) {
+               edac_mc_handle_error(ecc_type, mci, error_cnt, 0, 0, 0,
+                                    0, 0, -1, mci->ctl_name, "");
+               return;
+       }
+
+       dram_additional_info = readl(priv->emi_base + MLXBF_ADD_INFO);
+       err_prank = FIELD_GET(MLXBF_ADD_INFO__ERR_PRANK, dram_additional_info);
+
+       ecc_dimm = (err_prank >= 2 && priv->dimm_ranks[0] <= 2) ? 1 : 0;
+
+       edea0 = readl(priv->emi_base + MLXBF_ERR_ADDR_0);
+       edea1 = readl(priv->emi_base + MLXBF_ERR_ADDR_1);
+
+       ecc_dimm_addr = ((u64)edea1 << 32) | edea0;
+
+       edac_mc_handle_error(ecc_type, mci, error_cnt,
+                            PFN_DOWN(ecc_dimm_addr),
+                            offset_in_page(ecc_dimm_addr),
+                            syndrom, ecc_dimm, 0, 0, mci->ctl_name, "");
+}
+
+static void bluefield_edac_check(struct mem_ctl_info *mci)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       u32 ecc_count, single_error_count, double_error_count, ecc_error = 0;
+
+       /*
+        * The memory controller might not be initialized by the firmware
+        * when there isn't memory, which may lead to bad register readings.
+        */
+       if (mci->edac_cap == EDAC_FLAG_NONE)
+               return;
+
+       ecc_count = readl(priv->emi_base + MLXBF_ECC_CNT);
+       single_error_count = FIELD_GET(MLXBF_ECC_CNT__SERR_CNT, ecc_count);
+       double_error_count = FIELD_GET(MLXBF_ECC_CNT__DERR_CNT, ecc_count);
+
+       if (single_error_count) {
+               ecc_error |= MLXBF_ECC_ERR__SECC;
+
+               bluefield_gather_report_ecc(mci, single_error_count, 1);
+       }
+
+       if (double_error_count) {
+               ecc_error |= MLXBF_ECC_ERR__DECC;
+
+               bluefield_gather_report_ecc(mci, double_error_count, 0);
+       }
+
+       /* Write to clear reported errors. */
+       if (ecc_count)
+               writel(ecc_error, priv->emi_base + MLXBF_ECC_ERR);
+}
+
+/* Initialize the DIMMs information for the given memory controller. */
+static void bluefield_edac_init_dimms(struct mem_ctl_info *mci)
+{
+       struct bluefield_edac_priv *priv = mci->pvt_info;
+       int mem_ctrl_idx = mci->mc_idx;
+       struct dimm_info *dimm;
+       u64 smc_info, smc_arg;
+       int is_empty = 1, i;
+
+       for (i = 0; i < priv->dimm_per_mc; i++) {
+               dimm = mci->dimms[i];
+
+               smc_arg = mem_ctrl_idx << 16 | i;
+               smc_info = smc_call1(MLNX_SIP_GET_DIMM_INFO, smc_arg);
+
+               if (!FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info)) {
+                       dimm->mtype = MEM_EMPTY;
+                       continue;
+               }
+
+               is_empty = 0;
+
+               dimm->edac_mode = EDAC_SECDED;
+
+               if (FIELD_GET(MLXBF_DIMM_INFO__IS_NVDIMM, smc_info))
+                       dimm->mtype = MEM_NVDIMM;
+               else if (FIELD_GET(MLXBF_DIMM_INFO__IS_LRDIMM, smc_info))
+                       dimm->mtype = MEM_LRDDR4;
+               else if (FIELD_GET(MLXBF_DIMM_INFO__IS_RDIMM, smc_info))
+                       dimm->mtype = MEM_RDDR4;
+               else
+                       dimm->mtype = MEM_DDR4;
+
+               dimm->nr_pages =
+                       FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info) *
+                       (SZ_1G / PAGE_SIZE);
+               dimm->grain = MLXBF_EDAC_ERROR_GRAIN;
+
+               /* Mem controller for BlueField only supports x4, x8 and x16 */
+               switch (FIELD_GET(MLXBF_DIMM_INFO__PACKAGE_X, smc_info)) {
+               case 4:
+                       dimm->dtype = DEV_X4;
+                       break;
+               case 8:
+                       dimm->dtype = DEV_X8;
+                       break;
+               case 16:
+                       dimm->dtype = DEV_X16;
+                       break;
+               default:
+                       dimm->dtype = DEV_UNKNOWN;
+               }
+
+               priv->dimm_ranks[i] =
+                       FIELD_GET(MLXBF_DIMM_INFO__RANKS, smc_info);
+       }
+
+       if (is_empty)
+               mci->edac_cap = EDAC_FLAG_NONE;
+       else
+               mci->edac_cap = EDAC_FLAG_SECDED;
+}
+
+static int bluefield_edac_mc_probe(struct platform_device *pdev)
+{
+       struct bluefield_edac_priv *priv;
+       struct device *dev = &pdev->dev;
+       struct edac_mc_layer layers[1];
+       struct mem_ctl_info *mci;
+       struct resource *emi_res;
+       unsigned int mc_idx, dimm_count;
+       int rc, ret;
+
+       /* Read the MSS (Memory SubSystem) index from ACPI table. */
+       if (device_property_read_u32(dev, "mss_number", &mc_idx)) {
+               dev_warn(dev, "bf_edac: MSS number unknown\n");
+               return -EINVAL;
+       }
+
+       /* Read the DIMMs per MC from ACPI table. */
+       if (device_property_read_u32(dev, "dimm_per_mc", &dimm_count)) {
+               dev_warn(dev, "bf_edac: DIMMs per MC unknown\n");
+               return -EINVAL;
+       }
+
+       if (dimm_count > MLXBF_EDAC_MAX_DIMM_PER_MC) {
+               dev_warn(dev, "bf_edac: DIMMs per MC not valid\n");
+               return -EINVAL;
+       }
+
+       emi_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!emi_res)
+               return -EINVAL;
+
+       layers[0].type = EDAC_MC_LAYER_SLOT;
+       layers[0].size = dimm_count;
+       layers[0].is_virt_csrow = true;
+
+       mci = edac_mc_alloc(mc_idx, ARRAY_SIZE(layers), layers, sizeof(*priv));
+       if (!mci)
+               return -ENOMEM;
+
+       priv = mci->pvt_info;
+
+       priv->dimm_per_mc = dimm_count;
+       priv->emi_base = devm_ioremap_resource(dev, emi_res);
+       if (IS_ERR(priv->emi_base)) {
+               dev_err(dev, "failed to map EMI IO resource\n");
+               ret = PTR_ERR(priv->emi_base);
+               goto err;
+       }
+
+       mci->pdev = dev;
+       mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_RDDR4 |
+                        MEM_FLAG_LRDDR4 | MEM_FLAG_NVDIMM;
+       mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+
+       mci->mod_name = DRIVER_NAME;
+       mci->ctl_name = "BlueField_Memory_Controller";
+       mci->dev_name = dev_name(dev);
+       mci->edac_check = bluefield_edac_check;
+
+       /* Initialize mci with the actual populated DIMM information. */
+       bluefield_edac_init_dimms(mci);
+
+       platform_set_drvdata(pdev, mci);
+
+       /* Register with EDAC core */
+       rc = edac_mc_add_mc(mci);
+       if (rc) {
+               dev_err(dev, "failed to register with EDAC core\n");
+               ret = rc;
+               goto err;
+       }
+
+       /* Only POLL mode supported so far. */
+       edac_op_state = EDAC_OPSTATE_POLL;
+
+       return 0;
+
+err:
+       edac_mc_free(mci);
+
+       return ret;
+
+}
+
+static int bluefield_edac_mc_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+static const struct acpi_device_id bluefield_mc_acpi_ids[] = {
+       {"MLNXBF08", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(acpi, bluefield_mc_acpi_ids);
+
+static struct platform_driver bluefield_edac_mc_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .acpi_match_table = bluefield_mc_acpi_ids,
+       },
+       .probe = bluefield_edac_mc_probe,
+       .remove = bluefield_edac_mc_remove,
+};
+
+module_platform_driver(bluefield_edac_mc_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField memory edac driver");
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_LICENSE("GPL v2");
index 64922c8..e6fd079 100644 (file)
@@ -114,8 +114,8 @@ static const struct kernel_param_ops edac_report_ops = {
 
 module_param_cb(edac_report, &edac_report_ops, &edac_report, 0644);
 
-unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
-                                unsigned len)
+unsigned int edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+                                    unsigned int len)
 {
        struct mem_ctl_info *mci = dimm->mci;
        int i, n, count = 0;
@@ -236,9 +236,9 @@ EXPORT_SYMBOL_GPL(edac_mem_types);
  * At return, the pointer 'p' will be incremented to be used on a next call
  * to this function.
  */
-void *edac_align_ptr(void **p, unsigned size, int n_elems)
+void *edac_align_ptr(void **p, unsigned int size, int n_elems)
 {
-       unsigned align, r;
+       unsigned int align, r;
        void *ptr = *p;
 
        *p += size * n_elems;
@@ -275,38 +275,37 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems)
 
 static void _edac_mc_free(struct mem_ctl_info *mci)
 {
-       int i, chn, row;
        struct csrow_info *csr;
-       const unsigned int tot_dimms = mci->tot_dimms;
-       const unsigned int tot_channels = mci->num_cschannel;
-       const unsigned int tot_csrows = mci->nr_csrows;
+       int i, chn, row;
 
        if (mci->dimms) {
-               for (i = 0; i < tot_dimms; i++)
+               for (i = 0; i < mci->tot_dimms; i++)
                        kfree(mci->dimms[i]);
                kfree(mci->dimms);
        }
+
        if (mci->csrows) {
-               for (row = 0; row < tot_csrows; row++) {
+               for (row = 0; row < mci->nr_csrows; row++) {
                        csr = mci->csrows[row];
-                       if (csr) {
-                               if (csr->channels) {
-                                       for (chn = 0; chn < tot_channels; chn++)
-                                               kfree(csr->channels[chn]);
-                                       kfree(csr->channels);
-                               }
-                               kfree(csr);
+                       if (!csr)
+                               continue;
+
+                       if (csr->channels) {
+                               for (chn = 0; chn < mci->num_cschannel; chn++)
+                                       kfree(csr->channels[chn]);
+                               kfree(csr->channels);
                        }
+                       kfree(csr);
                }
                kfree(mci->csrows);
        }
        kfree(mci);
 }
 
-struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
-                                  unsigned n_layers,
+struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
+                                  unsigned int n_layers,
                                   struct edac_mc_layer *layers,
-                                  unsigned sz_pvt)
+                                  unsigned int sz_pvt)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer *layer;
@@ -314,9 +313,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        struct rank_info *chan;
        struct dimm_info *dimm;
        u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
-       unsigned pos[EDAC_MAX_LAYERS];
-       unsigned size, tot_dimms = 1, count = 1;
-       unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
+       unsigned int pos[EDAC_MAX_LAYERS];
+       unsigned int size, tot_dimms = 1, count = 1;
+       unsigned int tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
        void *pvt, *p, *ptr = NULL;
        int i, j, row, chn, n, len, off;
        bool per_rank = false;
@@ -1235,9 +1234,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        if (p > e->location)
                *(p - 1) = '\0';
 
-       /* Report the error via the trace interface */
-       grain_bits = fls_long(e->grain) + 1;
+       /* Sanity-check driver-supplied grain value. */
+       if (WARN_ON_ONCE(!e->grain))
+               e->grain = 1;
 
+       grain_bits = fls_long(e->grain - 1);
+
+       /* Report the error via the trace interface */
        if (IS_ENABLED(CONFIG_RAS))
                trace_mc_event(type, e->msg, e->label, e->error_count,
                               mci->mc_idx, e->top_layer, e->mid_layer,
index 4165e15..02aac5c 100644 (file)
@@ -122,10 +122,10 @@ do {                                                                      \
  *     On success, return a pointer to struct mem_ctl_info pointer;
  *     %NULL otherwise
  */
-struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
-                                  unsigned n_layers,
+struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
+                                  unsigned int n_layers,
                                   struct edac_mc_layer *layers,
-                                  unsigned sz_pvt);
+                                  unsigned int sz_pvt);
 
 /**
  * edac_get_owner - Return the owner's mod_name of EDAC MC
index 4386ea4..32d016f 100644 (file)
@@ -131,7 +131,7 @@ static const char * const edac_caps[] = {
 
 struct dev_ch_attribute {
        struct device_attribute attr;
-       int channel;
+       unsigned int channel;
 };
 
 #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
@@ -200,7 +200,7 @@ static ssize_t channel_dimm_label_show(struct device *dev,
                                       char *data)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
 
        /* if field has not been initialized, there is nothing to send */
@@ -216,7 +216,7 @@ static ssize_t channel_dimm_label_store(struct device *dev,
                                        const char *data, size_t count)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
        size_t copy_count = count;
 
@@ -240,7 +240,7 @@ static ssize_t channel_ce_count_show(struct device *dev,
                                     struct device_attribute *mattr, char *data)
 {
        struct csrow_info *csrow = to_csrow(dev);
-       unsigned chan = to_channel(mattr);
+       unsigned int chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
 
        return sprintf(data, "%u\n", rank->ce_count);
@@ -278,7 +278,7 @@ static void csrow_attr_release(struct device *dev)
 {
        struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
 
-       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(csrow);
 }
 
@@ -414,14 +414,16 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
        dev_set_name(&csrow->dev, "csrow%d", index);
        dev_set_drvdata(&csrow->dev, csrow);
 
-       edac_dbg(0, "creating (virtual) csrow node %s\n",
-                dev_name(&csrow->dev));
-
        err = device_add(&csrow->dev);
-       if (err)
+       if (err) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev));
                put_device(&csrow->dev);
+               return err;
+       }
 
-       return err;
+       edac_dbg(0, "device %s created\n", dev_name(&csrow->dev));
+
+       return 0;
 }
 
 /* Create a CSROW object under specifed edac_mc_device */
@@ -435,12 +437,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
                if (!nr_pages_per_csrow(csrow))
                        continue;
                err = edac_create_csrow_object(mci, mci->csrows[i], i);
-               if (err < 0) {
-                       edac_dbg(1,
-                                "failure: create csrow objects for csrow %d\n",
-                                i);
+               if (err < 0)
                        goto error;
-               }
        }
        return 0;
 
@@ -624,7 +622,7 @@ static void dimm_attr_release(struct device *dev)
 {
        struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
 
-       edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(dimm);
 }
 
@@ -653,12 +651,21 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        pm_runtime_forbid(&mci->dev);
 
        err = device_add(&dimm->dev);
-       if (err)
+       if (err) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev));
                put_device(&dimm->dev);
+               return err;
+       }
 
-       edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev));
+       if (IS_ENABLED(CONFIG_EDAC_DEBUG)) {
+               char location[80];
 
-       return err;
+               edac_dimm_info_location(dimm, location, sizeof(location));
+               edac_dbg(0, "device %s created at location %s\n",
+                       dev_name(&dimm->dev), location);
+       }
+
+       return 0;
 }
 
 /*
@@ -901,7 +908,7 @@ static void mci_attr_release(struct device *dev)
 {
        struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
 
-       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(mci);
 }
 
@@ -933,14 +940,15 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
        dev_set_drvdata(&mci->dev, mci);
        pm_runtime_forbid(&mci->dev);
 
-       edac_dbg(0, "creating device %s\n", dev_name(&mci->dev));
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
                put_device(&mci->dev);
-               goto out;
+               return err;
        }
 
+       edac_dbg(0, "device %s created\n", dev_name(&mci->dev));
+
        /*
         * Create the dimm/rank devices
         */
@@ -950,22 +958,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
                if (!dimm->nr_pages)
                        continue;
 
-#ifdef CONFIG_EDAC_DEBUG
-               edac_dbg(1, "creating dimm%d, located at ", i);
-               if (edac_debug_level >= 1) {
-                       int lay;
-                       for (lay = 0; lay < mci->n_layers; lay++)
-                               printk(KERN_CONT "%s %d ",
-                                       edac_layer_name[mci->layers[lay].type],
-                                       dimm->location[lay]);
-                       printk(KERN_CONT "\n");
-               }
-#endif
                err = edac_create_dimm_object(mci, dimm, i);
-               if (err) {
-                       edac_dbg(1, "failure: create dimm %d obj\n", i);
+               if (err)
                        goto fail_unregister_dimm;
-               }
        }
 
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
@@ -987,7 +982,6 @@ fail_unregister_dimm:
        }
        device_unregister(&mci->dev);
 
-out:
        return err;
 }
 
@@ -1011,14 +1005,14 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
                struct dimm_info *dimm = mci->dimms[i];
                if (dimm->nr_pages == 0)
                        continue;
-               edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev));
+               edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev));
                device_unregister(&dimm->dev);
        }
 }
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
-       edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
+       edac_dbg(1, "unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
 }
 
@@ -1029,7 +1023,7 @@ static void mc_attr_release(struct device *dev)
         * parent device, used to create the /sys/devices/mc sysfs node.
         * So, there are no attributes on it.
         */
-       edac_dbg(1, "Releasing device %s\n", dev_name(dev));
+       edac_dbg(1, "device %s released\n", dev_name(dev));
        kfree(dev);
 }
 
@@ -1044,10 +1038,8 @@ int __init edac_mc_sysfs_init(void)
        int err;
 
        mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
-       if (!mci_pdev) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!mci_pdev)
+               return -ENOMEM;
 
        mci_pdev->bus = edac_get_sysfs_subsys();
        mci_pdev->type = &mc_attr_type;
@@ -1055,17 +1047,15 @@ int __init edac_mc_sysfs_init(void)
        dev_set_name(mci_pdev, "mc");
 
        err = device_add(mci_pdev);
-       if (err < 0)
-               goto out_put_device;
+       if (err < 0) {
+               edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev));
+               put_device(mci_pdev);
+               return err;
+       }
 
        edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
 
        return 0;
-
- out_put_device:
-       put_device(mci_pdev);
- out:
-       return err;
 }
 
 void edac_mc_sysfs_exit(void)
index 7f19f1c..d413a0b 100644 (file)
@@ -68,7 +68,7 @@ struct memdev_dmi_entry {
 
 struct ghes_edac_dimm_fill {
        struct mem_ctl_info *mci;
-       unsigned count;
+       unsigned int count;
 };
 
 static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg)
index b506eef..251f2b6 100644 (file)
@@ -417,7 +417,8 @@ static const char *i5100_err_msg(unsigned err)
 }
 
 /* convert csrow index into a rank (per channel -- 0..5) */
-static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow)
+static unsigned int i5100_csrow_to_rank(const struct mem_ctl_info *mci,
+                                       unsigned int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
@@ -425,7 +426,8 @@ static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow)
 }
 
 /* convert csrow index into a channel (0..1) */
-static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow)
+static unsigned int i5100_csrow_to_chan(const struct mem_ctl_info *mci,
+                                       unsigned int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
@@ -653,11 +655,11 @@ static struct pci_dev *pci_get_device_func(unsigned vendor,
        return ret;
 }
 
-static unsigned long i5100_npages(struct mem_ctl_info *mci, int csrow)
+static unsigned long i5100_npages(struct mem_ctl_info *mci, unsigned int csrow)
 {
        struct i5100_priv *priv = mci->pvt_info;
-       const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow);
-       const unsigned chan = i5100_csrow_to_chan(mci, csrow);
+       const unsigned int chan_rank = i5100_csrow_to_rank(mci, csrow);
+       const unsigned int chan = i5100_csrow_to_chan(mci, csrow);
        unsigned addr_lines;
 
        /* dimm present? */
@@ -852,8 +854,8 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
        for (i = 0; i < mci->tot_dimms; i++) {
                struct dimm_info *dimm;
                const unsigned long npages = i5100_npages(mci, i);
-               const unsigned chan = i5100_csrow_to_chan(mci, i);
-               const unsigned rank = i5100_csrow_to_rank(mci, i);
+               const unsigned int chan = i5100_csrow_to_chan(mci, i);
+               const unsigned int rank = i5100_csrow_to_rank(mci, i);
 
                if (!npages)
                        continue;
index ca25f8f..1ad538b 100644 (file)
@@ -260,11 +260,14 @@ static u64 get_sideband_reg_base_addr(void)
        }
 }
 
+#define DNV_MCHBAR_SIZE  0x8000
+#define DNV_SB_PORT_SIZE 0x10000
 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name)
 {
        struct pci_dev *pdev;
        char *base;
        u64 addr;
+       unsigned long size;
 
        if (op == 4) {
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL);
@@ -279,15 +282,17 @@ static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *na
                        addr = get_mem_ctrl_hub_base_addr();
                        if (!addr)
                                return -ENODEV;
+                       size = DNV_MCHBAR_SIZE;
                } else {
                        /* MMIO via sideband register base address */
                        addr = get_sideband_reg_base_addr();
                        if (!addr)
                                return -ENODEV;
                        addr += (port << 16);
+                       size = DNV_SB_PORT_SIZE;
                }
 
-               base = ioremap((resource_size_t)addr, 0x10000);
+               base = ioremap((resource_size_t)addr, size);
                if (!base)
                        return -ENODEV;
 
index 1db780c..3caae7f 100644 (file)
@@ -927,17 +927,33 @@ fail:
        return status;
 }
 
+#define GET_EFI_CONFIG_TABLE(bits)                                     \
+static void *get_efi_config_table##bits(efi_system_table_t *_sys_table,        \
+                                       efi_guid_t guid)                \
+{                                                                      \
+       efi_system_table_##bits##_t *sys_table;                         \
+       efi_config_table_##bits##_t *tables;                            \
+       int i;                                                          \
+                                                                       \
+       sys_table = (typeof(sys_table))_sys_table;                      \
+       tables = (typeof(tables))(unsigned long)sys_table->tables;      \
+                                                                       \
+       for (i = 0; i < sys_table->nr_tables; i++) {                    \
+               if (efi_guidcmp(tables[i].guid, guid) != 0)             \
+                       continue;                                       \
+                                                                       \
+               return (void *)(unsigned long)tables[i].table;          \
+       }                                                               \
+                                                                       \
+       return NULL;                                                    \
+}
+GET_EFI_CONFIG_TABLE(32)
+GET_EFI_CONFIG_TABLE(64)
+
 void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
 {
-       efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables;
-       int i;
-
-       for (i = 0; i < sys_table->nr_tables; i++) {
-               if (efi_guidcmp(tables[i].guid, guid) != 0)
-                       continue;
-
-               return (void *)tables[i].table;
-       }
-
-       return NULL;
+       if (efi_is_64bit())
+               return get_efi_config_table64(sys_table, guid);
+       else
+               return get_efi_config_table32(sys_table, guid);
 }
index f82ccd3..84f4ff3 100644 (file)
@@ -103,7 +103,7 @@ static inline bool psci_power_state_loses_context(u32 state)
        return state & mask;
 }
 
-static inline bool psci_power_state_is_valid(u32 state)
+bool psci_power_state_is_valid(u32 state)
 {
        const u32 valid_mask = psci_has_ext_power_state() ?
                               PSCI_1_0_EXT_POWER_STATE_MASK :
@@ -277,175 +277,24 @@ static int __init psci_features(u32 psci_func_id)
 }
 
 #ifdef CONFIG_CPU_IDLE
-static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
-
-static int psci_dt_parse_state_node(struct device_node *np, u32 *state)
-{
-       int err = of_property_read_u32(np, "arm,psci-suspend-param", state);
-
-       if (err) {
-               pr_warn("%pOF missing arm,psci-suspend-param property\n", np);
-               return err;
-       }
-
-       if (!psci_power_state_is_valid(*state)) {
-               pr_warn("Invalid PSCI power state %#x\n", *state);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
-{
-       int i, ret = 0, count = 0;
-       u32 *psci_states;
-       struct device_node *state_node;
-
-       /* Count idle states */
-       while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
-                                             count))) {
-               count++;
-               of_node_put(state_node);
-       }
-
-       if (!count)
-               return -ENODEV;
-
-       psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
-       if (!psci_states)
-               return -ENOMEM;
-
-       for (i = 0; i < count; i++) {
-               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
-               ret = psci_dt_parse_state_node(state_node, &psci_states[i]);
-               of_node_put(state_node);
-
-               if (ret)
-                       goto free_mem;
-
-               pr_debug("psci-power-state %#x index %d\n", psci_states[i], i);
-       }
-
-       /* Idle states parsed correctly, initialize per-cpu pointer */
-       per_cpu(psci_power_state, cpu) = psci_states;
-       return 0;
-
-free_mem:
-       kfree(psci_states);
-       return ret;
-}
-
-#ifdef CONFIG_ACPI
-#include <acpi/processor.h>
-
-static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
-{
-       int i, count;
-       u32 *psci_states;
-       struct acpi_lpi_state *lpi;
-       struct acpi_processor *pr = per_cpu(processors, cpu);
-
-       if (unlikely(!pr || !pr->flags.has_lpi))
-               return -EINVAL;
-
-       count = pr->power.count - 1;
-       if (count <= 0)
-               return -ENODEV;
-
-       psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
-       if (!psci_states)
-               return -ENOMEM;
-
-       for (i = 0; i < count; i++) {
-               u32 state;
-
-               lpi = &pr->power.lpi_states[i + 1];
-               /*
-                * Only bits[31:0] represent a PSCI power_state while
-                * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification
-                */
-               state = lpi->address;
-               if (!psci_power_state_is_valid(state)) {
-                       pr_warn("Invalid PSCI power state %#x\n", state);
-                       kfree(psci_states);
-                       return -EINVAL;
-               }
-               psci_states[i] = state;
-       }
-       /* Idle states parsed correctly, initialize per-cpu pointer */
-       per_cpu(psci_power_state, cpu) = psci_states;
-       return 0;
-}
-#else
-static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
-{
-       return -EINVAL;
-}
-#endif
-
-int psci_cpu_init_idle(unsigned int cpu)
-{
-       struct device_node *cpu_node;
-       int ret;
-
-       /*
-        * If the PSCI cpu_suspend function hook has not been initialized
-        * idle states must not be enabled, so bail out
-        */
-       if (!psci_ops.cpu_suspend)
-               return -EOPNOTSUPP;
-
-       if (!acpi_disabled)
-               return psci_acpi_cpu_init_idle(cpu);
-
-       cpu_node = of_get_cpu_node(cpu, NULL);
-       if (!cpu_node)
-               return -ENODEV;
-
-       ret = psci_dt_cpu_init_idle(cpu_node, cpu);
-
-       of_node_put(cpu_node);
-
-       return ret;
-}
-
-static int psci_suspend_finisher(unsigned long index)
+static int psci_suspend_finisher(unsigned long state)
 {
-       u32 *state = __this_cpu_read(psci_power_state);
+       u32 power_state = state;
 
-       return psci_ops.cpu_suspend(state[index - 1],
-                                   __pa_symbol(cpu_resume));
+       return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume));
 }
 
-int psci_cpu_suspend_enter(unsigned long index)
+int psci_cpu_suspend_enter(u32 state)
 {
        int ret;
-       u32 *state = __this_cpu_read(psci_power_state);
-       /*
-        * idle state index 0 corresponds to wfi, should never be called
-        * from the cpu_suspend operations
-        */
-       if (WARN_ON_ONCE(!index))
-               return -EINVAL;
 
-       if (!psci_power_state_loses_context(state[index - 1]))
-               ret = psci_ops.cpu_suspend(state[index - 1], 0);
+       if (!psci_power_state_loses_context(state))
+               ret = psci_ops.cpu_suspend(state, 0);
        else
-               ret = cpu_suspend(index, psci_suspend_finisher);
+               ret = cpu_suspend(state, psci_suspend_finisher);
 
        return ret;
 }
-
-/* ARM specific CPU idle operations */
-#ifdef CONFIG_ARM
-static const struct cpuidle_ops psci_cpuidle_ops __initconst = {
-       .suspend = psci_cpu_suspend_enter,
-       .init = psci_dt_cpu_init_idle,
-};
-
-CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops);
-#endif
 #endif
 
 static int psci_system_suspend(unsigned long unused)
index f365944..6a44539 100644 (file)
@@ -228,8 +228,11 @@ out_free_cpus:
 
 static void dummy_callback(struct timer_list *unused) {}
 
-static int suspend_cpu(int index, bool broadcast)
+static int suspend_cpu(struct cpuidle_device *dev,
+                      struct cpuidle_driver *drv, int index)
 {
+       struct cpuidle_state *state = &drv->states[index];
+       bool broadcast = state->flags & CPUIDLE_FLAG_TIMER_STOP;
        int ret;
 
        arch_cpu_idle_enter();
@@ -254,11 +257,7 @@ static int suspend_cpu(int index, bool broadcast)
                }
        }
 
-       /*
-        * Replicate the common ARM cpuidle enter function
-        * (arm_enter_idle_state).
-        */
-       ret = CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, index);
+       ret = state->enter(dev, drv, index);
 
        if (broadcast)
                tick_broadcast_exit();
@@ -301,9 +300,8 @@ static int suspend_test_thread(void *arg)
                 * doesn't use PSCI).
                 */
                for (index = 1; index < drv->state_count; ++index) {
-                       struct cpuidle_state *state = &drv->states[index];
-                       bool broadcast = state->flags & CPUIDLE_FLAG_TIMER_STOP;
                        int ret;
+                       struct cpuidle_state *state = &drv->states[index];
 
                        /*
                         * Set the timer to wake this CPU up in some time (which
@@ -318,7 +316,7 @@ static int suspend_test_thread(void *arg)
                        /* IRQs must be disabled during suspend operations. */
                        local_irq_disable();
 
-                       ret = suspend_cpu(index, broadcast);
+                       ret = suspend_cpu(dev, drv, index);
 
                        /*
                         * We have woken up. Re-enable IRQs to handle any
index a13f224..0221dee 100644 (file)
@@ -210,7 +210,7 @@ static int altera_ps_write_complete(struct fpga_manager *mgr,
                return -EIO;
        }
 
-       if (!IS_ERR(conf->confd)) {
+       if (conf->confd) {
                if (!gpiod_get_raw_value_cansleep(conf->confd)) {
                        dev_err(&mgr->dev, "CONF_DONE is inactive!\n");
                        return -EIO;
@@ -289,10 +289,13 @@ static int altera_ps_probe(struct spi_device *spi)
                return PTR_ERR(conf->status);
        }
 
-       conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN);
+       conf->confd = devm_gpiod_get_optional(&spi->dev, "confd", GPIOD_IN);
        if (IS_ERR(conf->confd)) {
-               dev_warn(&spi->dev, "Not using confd gpio: %ld\n",
-                        PTR_ERR(conf->confd));
+               dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
+                       PTR_ERR(conf->confd));
+               return PTR_ERR(conf->confd);
+       } else if (!conf->confd) {
+               dev_warn(&spi->dev, "Not using confd gpio");
        }
 
        /* Register manager with unique name */
index 343153d..004dc03 100644 (file)
@@ -38,8 +38,7 @@
 #define SCOM_STATUS_PIB_RESP_MASK      0x00007000
 #define SCOM_STATUS_PIB_RESP_SHIFT     12
 
-#define SCOM_STATUS_ANY_ERR            (SCOM_STATUS_ERR_SUMMARY | \
-                                        SCOM_STATUS_PROTECTION | \
+#define SCOM_STATUS_ANY_ERR            (SCOM_STATUS_PROTECTION | \
                                         SCOM_STATUS_PARITY |     \
                                         SCOM_STATUS_PIB_ABORT | \
                                         SCOM_STATUS_PIB_RESP_MASK)
@@ -251,11 +250,6 @@ static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
        /* Return -EBUSY on PIB abort to force a retry */
        if (status & SCOM_STATUS_PIB_ABORT)
                return -EBUSY;
-       if (status & SCOM_STATUS_ERR_SUMMARY) {
-               fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
-                                sizeof(uint32_t));
-               return -EIO;
-       }
        return 0;
 }
 
index 34c679c..305b47e 100644 (file)
@@ -288,7 +288,7 @@ config GPIO_IXP4XX
        depends on ARM # For <asm/mach-types.h>
        depends on ARCH_IXP4XX
        select GPIO_GENERIC
-       select IRQ_DOMAIN
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        help
          Say yes here to support the GPIO functionality of a number of Intel
@@ -546,6 +546,7 @@ config GPIO_THUNDERX
        tristate "Cavium ThunderX/OCTEON-TX GPIO"
        depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
        depends on PCI_MSI
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        select IRQ_FASTEOI_HIERARCHY_HANDLERS
        help
@@ -1472,7 +1473,6 @@ endmenu
 
 config GPIO_MOCKUP
        tristate "GPIO Testing Driver"
-       depends on GPIOLIB
        select IRQ_SIM
        help
          This enables GPIO Testing driver, which provides a way to test GPIO
index 87d659a..f3e051f 100644 (file)
@@ -67,7 +67,6 @@ obj-$(CONFIG_GPIO_IT87)                       += gpio-it87.o
 obj-$(CONFIG_GPIO_IXP4XX)              += gpio-ixp4xx.o
 obj-$(CONFIG_GPIO_JANZ_TTL)            += gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)              += gpio-kempld.o
-obj-$(CONFIG_ARCH_KS8695)              += gpio-ks8695.o
 obj-$(CONFIG_GPIO_LOONGSON1)           += gpio-loongson1.o
 obj-$(CONFIG_GPIO_LOONGSON)            += gpio-loongson.o
 obj-$(CONFIG_GPIO_LP3943)              += gpio-lp3943.o
index c07fad9..5640efe 100644 (file)
@@ -142,7 +142,7 @@ static const struct gpio_chip template_chip = {
 static int arizona_gpio_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
-       struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
+       struct arizona_pdata *pdata = &arizona->pdata;
        struct arizona_gpio *arizona_gpio;
        int ret;
 
@@ -177,7 +177,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                arizona_gpio->gpio_chip.base = pdata->gpio_base;
        else
                arizona_gpio->gpio_chip.base = -1;
index 13d80bf..09e53c5 100644 (file)
@@ -52,6 +52,7 @@ struct aspeed_gpio_config {
  */
 struct aspeed_gpio {
        struct gpio_chip chip;
+       struct irq_chip irqc;
        spinlock_t lock;
        void __iomem *base;
        int irq;
@@ -661,12 +662,14 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
        struct gpio_chip *gc = irq_desc_get_handler_data(desc);
        struct irq_chip *ic = irq_desc_get_chip(desc);
        struct aspeed_gpio *data = gpiochip_get_data(gc);
-       unsigned int i, p, girq;
+       unsigned int i, p, girq, banks;
        unsigned long reg;
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
 
        chained_irq_enter(ic, desc);
 
-       for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) {
+       banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
+       for (i = 0; i < banks; i++) {
                const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
 
                reg = ioread32(bank_reg(data, bank, reg_irq_status));
@@ -681,16 +684,11 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
        chained_irq_exit(ic, desc);
 }
 
-static struct irq_chip aspeed_gpio_irqchip = {
-       .name           = "aspeed-gpio",
-       .irq_ack        = aspeed_gpio_irq_ack,
-       .irq_mask       = aspeed_gpio_irq_mask,
-       .irq_unmask     = aspeed_gpio_irq_unmask,
-       .irq_set_type   = aspeed_gpio_set_type,
-};
-
-static void set_irq_valid_mask(struct aspeed_gpio *gpio)
+static void aspeed_init_irq_valid_mask(struct gpio_chip *gc,
+                                      unsigned long *valid_mask,
+                                      unsigned int ngpios)
 {
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
        const struct aspeed_bank_props *props = gpio->config->props;
 
        while (!is_bank_props_sentinel(props)) {
@@ -701,42 +699,16 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
                for_each_clear_bit(offset, &input, 32) {
                        unsigned int i = props->bank * 32 + offset;
 
-                       if (i >= gpio->config->nr_gpios)
+                       if (i >= gpio->chip.ngpio)
                                break;
 
-                       clear_bit(i, gpio->chip.irq.valid_mask);
+                       clear_bit(i, valid_mask);
                }
 
                props++;
        }
 }
 
-static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
-               struct platform_device *pdev)
-{
-       int rc;
-
-       rc = platform_get_irq(pdev, 0);
-       if (rc < 0)
-               return rc;
-
-       gpio->irq = rc;
-
-       set_irq_valid_mask(gpio);
-
-       rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
-                       0, handle_bad_irq, IRQ_TYPE_NONE);
-       if (rc) {
-               dev_info(&pdev->dev, "Could not add irqchip\n");
-               return rc;
-       }
-
-       gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip,
-                                    gpio->irq, aspeed_gpio_irq_handler);
-
-       return 0;
-}
-
 static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip,
                                        unsigned int offset, bool enable)
 {
@@ -1040,10 +1012,10 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc,
        unsigned long flags;
 
        if (!gpio->cf_copro_bankmap)
-               gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL);
+               gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL);
        if (!gpio->cf_copro_bankmap)
                return -ENOMEM;
-       if (offset < 0 || offset > gpio->config->nr_gpios)
+       if (offset < 0 || offset > gpio->chip.ngpio)
                return -EINVAL;
        bindex = offset >> 3;
 
@@ -1088,7 +1060,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
        if (!gpio->cf_copro_bankmap)
                return -ENXIO;
 
-       if (offset < 0 || offset > gpio->config->nr_gpios)
+       if (offset < 0 || offset > gpio->chip.ngpio)
                return -EINVAL;
        bindex = offset >> 3;
 
@@ -1141,9 +1113,25 @@ static const struct aspeed_gpio_config ast2500_config =
        /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */
        { .nr_gpios = 232, .props = ast2500_bank_props, };
 
+static const struct aspeed_bank_props ast2600_bank_props[] = {
+       /*     input      output   */
+       {5, 0xffffffff,  0x0000ffff}, /* U/V/W/X */
+       {6, 0xffff0000,  0x0fff0000}, /* Y/Z */
+       { },
+};
+
+static const struct aspeed_gpio_config ast2600_config =
+       /*
+        * ast2600 has two controllers one with 208 GPIOs and one with 36 GPIOs.
+        * We expect ngpio being set in the device tree and this is a fallback
+        * option.
+        */
+       { .nr_gpios = 208, .props = ast2600_bank_props, };
+
 static const struct of_device_id aspeed_gpio_of_table[] = {
        { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, },
        { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, },
+       { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, },
        {}
 };
 MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
@@ -1152,7 +1140,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 {
        const struct of_device_id *gpio_id;
        struct aspeed_gpio *gpio;
-       int rc, i, banks;
+       int rc, i, banks, err;
+       u32 ngpio;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
        if (!gpio)
@@ -1178,7 +1167,10 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
        gpio->config = gpio_id->data;
 
        gpio->chip.parent = &pdev->dev;
-       gpio->chip.ngpio = gpio->config->nr_gpios;
+       err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio);
+       gpio->chip.ngpio = (u16) ngpio;
+       if (err)
+               gpio->chip.ngpio = gpio->config->nr_gpios;
        gpio->chip.direction_input = aspeed_gpio_dir_in;
        gpio->chip.direction_output = aspeed_gpio_dir_out;
        gpio->chip.get_direction = aspeed_gpio_get_direction;
@@ -1189,10 +1181,9 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
        gpio->chip.set_config = aspeed_gpio_set_config;
        gpio->chip.label = dev_name(&pdev->dev);
        gpio->chip.base = -1;
-       gpio->chip.irq.need_valid_mask = true;
 
        /* Allocate a cache of the output registers */
-       banks = gpio->config->nr_gpios >> 5;
+       banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
        gpio->dcache = devm_kcalloc(&pdev->dev,
                                    banks, sizeof(u32), GFP_KERNEL);
        if (!gpio->dcache)
@@ -1212,16 +1203,42 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
                aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
        }
 
-       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
-       if (rc < 0)
-               return rc;
+       /* Optionally set up an irqchip if there is an IRQ */
+       rc = platform_get_irq(pdev, 0);
+       if (rc > 0) {
+               struct gpio_irq_chip *girq;
+
+               gpio->irq = rc;
+               girq = &gpio->chip.irq;
+               girq->chip = &gpio->irqc;
+               girq->chip->name = dev_name(&pdev->dev);
+               girq->chip->irq_ack = aspeed_gpio_irq_ack;
+               girq->chip->irq_mask = aspeed_gpio_irq_mask;
+               girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
+               girq->chip->irq_set_type = aspeed_gpio_set_type;
+               girq->parent_handler = aspeed_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = gpio->irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_bad_irq;
+               girq->init_valid_mask = aspeed_init_irq_valid_mask;
+       }
 
        gpio->offset_timer =
                devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
        if (!gpio->offset_timer)
                return -ENOMEM;
 
-       return aspeed_gpio_setup_irqs(gpio, pdev);
+       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (rc < 0)
+               return rc;
+
+       return 0;
 }
 
 static struct platform_driver aspeed_gpio_driver = {
index fd85605..0c1ead1 100644 (file)
@@ -36,7 +36,7 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
                break;
        default:
                dev_err(bdgpio->chip.dev,
-                       "Invalid debouce value %u\n", debounce);
+                       "Invalid debounce value %u\n", debounce);
                return -EINVAL;
        }
        return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
@@ -153,7 +153,7 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
 
 static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-       int ret = -EINVAL;
+       int ret;
        struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
 
        /*
index af936dc..05e3f99 100644 (file)
@@ -636,10 +636,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
 
        if (of_property_read_bool(np, "interrupt-controller")) {
                priv->parent_irq = platform_get_irq(pdev, 0);
-               if (priv->parent_irq <= 0) {
-                       dev_err(dev, "Couldn't get IRQ");
+               if (priv->parent_irq <= 0)
                        return -ENOENT;
-               }
        } else {
                priv->parent_irq = -ENOENT;
        }
index 712ae21..a4d3239 100644 (file)
@@ -214,27 +214,33 @@ static int cdns_gpio_probe(struct platform_device *pdev)
                goto err_revert_dir;
        }
 
-       ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
-               goto err_disable_clk;
-       }
-
        /*
-        * irq_chip support
+        * Optional irq_chip support
         */
        irq = platform_get_irq(pdev, 0);
        if (irq >= 0) {
-               ret = gpiochip_irqchip_add(&cgpio->gc, &cdns_gpio_irqchip,
-                                          0, handle_level_irq,
-                                          IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(&pdev->dev, "Could not add irqchip, %d\n",
-                               ret);
+               struct gpio_irq_chip *girq;
+
+               girq = &cgpio->gc.irq;
+               girq->chip = &cdns_gpio_irqchip;
+               girq->parent_handler = cdns_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents) {
+                       ret = -ENOMEM;
                        goto err_disable_clk;
                }
-               gpiochip_set_chained_irqchip(&cgpio->gc, &cdns_gpio_irqchip,
-                                            irq, cdns_gpio_irq_handler);
+               girq->parents[0] = irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+       }
+
+       ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+               goto err_disable_clk;
        }
 
        cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE);
index 8cbc94d..ff19a8a 100644 (file)
@@ -137,7 +137,6 @@ static int creg_gpio_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct creg_gpio *hcg;
-       struct resource *mem;
        u32 ngpios;
        int ret;
 
@@ -145,8 +144,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
        if (!hcg)
                return -ENOMEM;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hcg->regs = devm_ioremap_resource(dev, mem);
+       hcg->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hcg->regs))
                return PTR_ERR(hcg->regs);
 
index 3108be5..92e127e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 #define GPIO_SWPORTA_DR                0x00
 #define GPIO_SWPORTA_DDR       0x04
index 7b9ac4a..fe7a73f 100644 (file)
@@ -584,10 +584,8 @@ static int sprd_eic_probe(struct platform_device *pdev)
        sprd_eic->type = pdata->type;
 
        sprd_eic->irq = platform_get_irq(pdev, 0);
-       if (sprd_eic->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get EIC interrupt.\n");
+       if (sprd_eic->irq < 0)
                return sprd_eic->irq;
-       }
 
        for (i = 0; i < SPRD_EIC_MAX_BANK; i++) {
                /*
index a879512..620f25b 100644 (file)
@@ -272,11 +272,12 @@ static int em_gio_probe(struct platform_device *pdev)
        struct resource *io[2], *irq[2];
        struct gpio_chip *gpio_chip;
        struct irq_chip *irq_chip;
-       const char *name = dev_name(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       const char *name = dev_name(dev);
        unsigned int ngpios;
        int ret;
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+       p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
 
@@ -290,27 +291,27 @@ static int em_gio_probe(struct platform_device *pdev)
        irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
 
        if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
-               dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
+               dev_err(dev, "missing IRQ or IOMEM\n");
                return -EINVAL;
        }
 
-       p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
+       p->base0 = devm_ioremap_nocache(dev, io[0]->start,
                                        resource_size(io[0]));
        if (!p->base0)
                return -ENOMEM;
 
-       p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
+       p->base1 = devm_ioremap_nocache(dev, io[1]->start,
                                   resource_size(io[1]));
        if (!p->base1)
                return -ENOMEM;
 
-       if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
-               dev_err(&pdev->dev, "Missing ngpios OF property\n");
+       if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
+               dev_err(dev, "Missing ngpios OF property\n");
                return -EINVAL;
        }
 
        gpio_chip = &p->gpio_chip;
-       gpio_chip->of_node = pdev->dev.of_node;
+       gpio_chip->of_node = dev->of_node;
        gpio_chip->direction_input = em_gio_direction_input;
        gpio_chip->get = em_gio_get;
        gpio_chip->direction_output = em_gio_direction_output;
@@ -319,7 +320,7 @@ static int em_gio_probe(struct platform_device *pdev)
        gpio_chip->request = em_gio_request;
        gpio_chip->free = em_gio_free;
        gpio_chip->label = name;
-       gpio_chip->parent = &pdev->dev;
+       gpio_chip->parent = dev;
        gpio_chip->owner = THIS_MODULE;
        gpio_chip->base = -1;
        gpio_chip->ngpio = ngpios;
@@ -333,33 +334,33 @@ static int em_gio_probe(struct platform_device *pdev)
        irq_chip->irq_release_resources = em_gio_irq_relres;
        irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
 
-       p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0,
+       p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0,
                                              &em_gio_irq_domain_ops, p);
        if (!p->irq_domain) {
-               dev_err(&pdev->dev, "cannot initialize irq domain\n");
+               dev_err(dev, "cannot initialize irq domain\n");
                return -ENXIO;
        }
 
-       ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove,
+       ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove,
                                       p->irq_domain);
        if (ret)
                return ret;
 
-       if (devm_request_irq(&pdev->dev, irq[0]->start,
+       if (devm_request_irq(dev, irq[0]->start,
                             em_gio_irq_handler, 0, name, p)) {
-               dev_err(&pdev->dev, "failed to request low IRQ\n");
+               dev_err(dev, "failed to request low IRQ\n");
                return -ENOENT;
        }
 
-       if (devm_request_irq(&pdev->dev, irq[1]->start,
+       if (devm_request_irq(dev, irq[1]->start,
                             em_gio_irq_handler, 0, name, p)) {
-               dev_err(&pdev->dev, "failed to request high IRQ\n");
+               dev_err(dev, "failed to request high IRQ\n");
                return -ENOENT;
        }
 
-       ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
+       ret = devm_gpiochip_add_data(dev, gpio_chip, p);
        if (ret) {
-               dev_err(&pdev->dev, "failed to add GPIO controller\n");
+               dev_err(dev, "failed to add GPIO controller\n");
                return ret;
        }
 
index a90870a..226da8d 100644 (file)
@@ -269,56 +269,6 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
        .irq_set_type   = ep93xx_gpio_irq_type,
 };
 
-static int ep93xx_gpio_init_irq(struct platform_device *pdev,
-                               struct ep93xx_gpio *epg)
-{
-       int ab_parent_irq = platform_get_irq(pdev, 0);
-       struct device *dev = &pdev->dev;
-       int gpio_irq;
-       int ret;
-       int i;
-
-       /* The A bank */
-       ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
-                                   64, handle_level_irq,
-                                   IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "Could not add irqchip 0\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
-                                    ab_parent_irq,
-                                    ep93xx_gpio_ab_irq_handler);
-
-       /* The B bank */
-       ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
-                                   72, handle_level_irq,
-                                   IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "Could not add irqchip 1\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
-                                    ab_parent_irq,
-                                    ep93xx_gpio_ab_irq_handler);
-
-       /* The F bank */
-       for (i = 0; i < 8; i++) {
-               gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
-               irq_set_chip_data(gpio_irq, &epg->gc[5]);
-               irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
-                                        handle_level_irq);
-               irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
-       }
-
-       for (i = 1; i <= 8; i++)
-               irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
-                                                ep93xx_gpio_f_irq_handler,
-                                                &epg->gc[i]);
-       return 0;
-}
-
-
 /*************************************************************************
  * gpiolib interface for EP93xx on-chip GPIOs
  *************************************************************************/
@@ -328,26 +278,33 @@ struct ep93xx_gpio_bank {
        int             dir;
        int             base;
        bool            has_irq;
+       bool            has_hierarchical_irq;
+       unsigned int    irq_base;
 };
 
-#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
+#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \
        {                                                       \
                .label          = _label,                       \
                .data           = _data,                        \
                .dir            = _dir,                         \
                .base           = _base,                        \
                .has_irq        = _has_irq,                     \
+               .has_hierarchical_irq = _has_hier,              \
+               .irq_base       = _irq_base,                    \
        }
 
 static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
-       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
-       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
-       EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
-       EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
-       EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
-       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
-       EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
-       EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
+       /* Bank A has 8 IRQs */
+       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64),
+       /* Bank B has 8 IRQs */
+       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72),
+       EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0),
+       EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0),
+       EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0),
+       /* Bank F has 8 IRQs */
+       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0),
+       EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0),
+       EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0),
 };
 
 static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
@@ -369,12 +326,15 @@ static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
        return EP93XX_GPIO_F_IRQ_BASE + offset;
 }
 
-static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
+static int ep93xx_gpio_add_bank(struct gpio_chip *gc,
+                               struct platform_device *pdev,
                                struct ep93xx_gpio *epg,
                                struct ep93xx_gpio_bank *bank)
 {
        void __iomem *data = epg->base + bank->data;
        void __iomem *dir = epg->base + bank->dir;
+       struct device *dev = &pdev->dev;
+       struct gpio_irq_chip *girq;
        int err;
 
        err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
@@ -384,8 +344,59 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
        gc->label = bank->label;
        gc->base = bank->base;
 
-       if (bank->has_irq)
+       girq = &gc->irq;
+       if (bank->has_irq || bank->has_hierarchical_irq) {
                gc->set_config = ep93xx_gpio_set_config;
+               girq->chip = &ep93xx_gpio_irq_chip;
+       }
+
+       if (bank->has_irq) {
+               int ab_parent_irq = platform_get_irq(pdev, 0);
+
+               girq->parent_handler = ep93xx_gpio_ab_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+               girq->parents[0] = ab_parent_irq;
+               girq->first = bank->irq_base;
+       }
+
+       /* Only bank F has especially funky IRQ handling */
+       if (bank->has_hierarchical_irq) {
+               int gpio_irq;
+               int i;
+
+               /*
+                * FIXME: convert this to use hierarchical IRQ support!
+                * this requires fixing the root irqchip to be hierarchial.
+                */
+               girq->parent_handler = ep93xx_gpio_f_irq_handler;
+               girq->num_parents = 8;
+               girq->parents = devm_kcalloc(dev, 8,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               /* Pick resources 1..8 for these IRQs */
+               for (i = 1; i <= 8; i++)
+                       girq->parents[i - 1] = platform_get_irq(pdev, i);
+               for (i = 0; i < 8; i++) {
+                       gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
+                       irq_set_chip_data(gpio_irq, &epg->gc[5]);
+                       irq_set_chip_and_handler(gpio_irq,
+                                                &ep93xx_gpio_irq_chip,
+                                                handle_level_irq);
+                       irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
+               }
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+               gc->to_irq = ep93xx_gpio_f_to_irq;
+       }
 
        return devm_gpiochip_add_data(dev, gc, epg);
 }
@@ -407,16 +418,11 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
                struct gpio_chip *gc = &epg->gc[i];
                struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
 
-               if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
+               if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
                        dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
                                 bank->label);
-               /* Only bank F has especially funky IRQ handling */
-               if (i == 5)
-                       gc->to_irq = ep93xx_gpio_f_to_irq;
        }
 
-       ep93xx_gpio_init_irq(pdev, epg);
-
        return 0;
 }
 
index 250e71f..fbddb16 100644 (file)
@@ -290,16 +290,14 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
                                     GFP_KERNEL);
-       if (!girq->parents)
-               return -ENOMEM;
+       if (!girq->parents) {
+               ret = -ENOMEM;
+               goto dis_clk;
+       }
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_bad_irq;
        girq->parents[0] = irq;
 
-       ret = devm_gpiochip_add_data(dev, &g->gc, g);
-       if (ret)
-               goto dis_clk;
-
        /* Disable, unmask and clear all interrupts */
        writel(0x0, g->base + GPIO_INT_EN);
        writel(0x0, g->base + GPIO_INT_MASK);
@@ -308,6 +306,10 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        /* Clear any use of debounce */
        writel(0x0, g->base + GPIO_DEBOUNCE_EN);
 
+       ret = devm_gpiochip_add_data(dev, &g->gc, g);
+       if (ret)
+               goto dis_clk;
+
        platform_set_drvdata(pdev, g);
        dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
 
index 0937b60..08234e6 100644 (file)
@@ -408,8 +408,6 @@ static int grgpio_probe(struct platform_device *ofdev)
                                 * Continue without irq functionality for that
                                 * gpio line
                                 */
-                               dev_err(priv->dev,
-                                       "Failed to get irq for offset %d\n", i);
                                continue;
                        }
                        priv->uirqs[lirq->index].uirq = ret;
index e5fa00f..4a17599 100644 (file)
@@ -244,43 +244,45 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
                ngpios = 32;
        hlwd->gpioc.ngpio = ngpios;
 
-       res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
-       if (res)
-               return res;
-
        /* Mask and ack all interrupts */
        iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK);
        iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG);
 
        /*
         * If this GPIO controller is not marked as an interrupt controller in
-        * the DT, return.
+        * the DT, skip interrupt support.
         */
-       if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller"))
-               return 0;
-
-       hlwd->irq = platform_get_irq(pdev, 0);
-       if (hlwd->irq < 0) {
-               dev_info(&pdev->dev, "platform_get_irq returned %d\n",
-                        hlwd->irq);
-               return hlwd->irq;
+       if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) {
+               struct gpio_irq_chip *girq;
+
+               hlwd->irq = platform_get_irq(pdev, 0);
+               if (hlwd->irq < 0) {
+                       dev_info(&pdev->dev, "platform_get_irq returned %d\n",
+                                hlwd->irq);
+                       return hlwd->irq;
+               }
+
+               hlwd->irqc.name = dev_name(&pdev->dev);
+               hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
+               hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
+               hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
+               hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
+
+               girq = &hlwd->gpioc.irq;
+               girq->chip = &hlwd->irqc;
+               girq->parent_handler = hlwd_gpio_irqhandler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = hlwd->irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
        }
 
-       hlwd->irqc.name = dev_name(&pdev->dev);
-       hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
-       hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
-       hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
-       hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
-
-       res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0,
-                                  handle_level_irq, IRQ_TYPE_NONE);
-       if (res)
-               return res;
-
-       gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc,
-                                    hlwd->irq, hlwd_gpio_irqhandler);
-
-       return 0;
+       return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
 }
 
 static const struct of_device_id hlwd_gpio_match[] = {
index 9d3ac51..6eb56f7 100644 (file)
@@ -118,20 +118,6 @@ static void egpio_handler(struct irq_desc *desc)
        }
 }
 
-int htc_egpio_get_wakeup_irq(struct device *dev)
-{
-       struct egpio_info *ei = dev_get_drvdata(dev);
-
-       /* Read current pins. */
-       u16 readval = egpio_readw(ei, ei->ack_register);
-       /* Ack/unmask interrupts. */
-       ack_irqs(ei);
-       /* Return first set pin. */
-       readval &= ei->irqs_enabled;
-       return ei->irq_start + ffs(readval) - 1;
-}
-EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
-
 static inline int egpio_pos(struct egpio_info *ei, int bit)
 {
        return bit >> ei->reg_shift;
index 4e803ba..4d835f9 100644 (file)
@@ -329,6 +329,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
        u32 gpio_base;
        u32 irq_base;
        int retval;
+       struct gpio_irq_chip *girq;
        struct intel_mid_gpio_ddata *ddata =
                                (struct intel_mid_gpio_ddata *)id->driver_data;
 
@@ -369,6 +370,22 @@ static int intel_gpio_probe(struct pci_dev *pdev,
 
        spin_lock_init(&priv->lock);
 
+       girq = &priv->chip.irq;
+       girq->chip = &intel_mid_irqchip;
+       girq->parent_handler = intel_mid_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = pdev->irq;
+       girq->first = irq_base;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_simple_irq;
+
+       intel_mid_irq_init_hw(priv);
+
        pci_set_drvdata(pdev, priv);
        retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
        if (retval) {
@@ -376,24 +393,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
                return retval;
        }
 
-       retval = gpiochip_irqchip_add(&priv->chip,
-                                     &intel_mid_irqchip,
-                                     irq_base,
-                                     handle_simple_irq,
-                                     IRQ_TYPE_NONE);
-       if (retval) {
-               dev_err(&pdev->dev,
-                       "could not connect irqchip to gpiochip\n");
-               return retval;
-       }
-
-       intel_mid_irq_init_hw(priv);
-
-       gpiochip_set_chained_irqchip(&priv->chip,
-                                    &intel_mid_irqchip,
-                                    pdev->irq,
-                                    intel_mid_irq_handler);
-
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
 
index 670c2a8..b3b0506 100644 (file)
@@ -47,7 +47,6 @@
  * @dev: containing device for this instance
  * @fwnode: the fwnode for this GPIO chip
  * @gc: gpiochip for this instance
- * @domain: irqdomain for this chip instance
  * @base: remapped I/O-memory base
  * @irq_edge: Each bit represents an IRQ: 1: edge-triggered,
  * 0: level triggered
@@ -56,48 +55,22 @@ struct ixp4xx_gpio {
        struct device *dev;
        struct fwnode_handle *fwnode;
        struct gpio_chip gc;
-       struct irq_domain *domain;
        void __iomem *base;
        unsigned long long irq_edge;
 };
 
-/**
- * struct ixp4xx_gpio_map - IXP4 GPIO to parent IRQ map
- * @gpio_offset: offset of the IXP4 GPIO line
- * @parent_hwirq: hwirq on the parent IRQ controller
- */
-struct ixp4xx_gpio_map {
-       int gpio_offset;
-       int parent_hwirq;
-};
-
-/* GPIO lines 0..12 have corresponding IRQs, GPIOs 13..15 have no IRQs */
-const struct ixp4xx_gpio_map ixp4xx_gpiomap[] = {
-       { .gpio_offset = 0, .parent_hwirq = 6 },
-       { .gpio_offset = 1, .parent_hwirq = 7 },
-       { .gpio_offset = 2, .parent_hwirq = 19 },
-       { .gpio_offset = 3, .parent_hwirq = 20 },
-       { .gpio_offset = 4, .parent_hwirq = 21 },
-       { .gpio_offset = 5, .parent_hwirq = 22 },
-       { .gpio_offset = 6, .parent_hwirq = 23 },
-       { .gpio_offset = 7, .parent_hwirq = 24 },
-       { .gpio_offset = 8, .parent_hwirq = 25 },
-       { .gpio_offset = 9, .parent_hwirq = 26 },
-       { .gpio_offset = 10, .parent_hwirq = 27 },
-       { .gpio_offset = 11, .parent_hwirq = 28 },
-       { .gpio_offset = 12, .parent_hwirq = 29 },
-};
-
 static void ixp4xx_gpio_irq_ack(struct irq_data *d)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
 
        __raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
 }
 
 static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
 
        /* ACK when unmasking if not edge-triggered */
        if (!(g->irq_edge & BIT(d->hwirq)))
@@ -108,7 +81,8 @@ static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
 
 static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
        int line = d->hwirq;
        unsigned long flags;
        u32 int_style;
@@ -187,122 +161,31 @@ static struct irq_chip ixp4xx_gpio_irqchip = {
        .irq_set_type = ixp4xx_gpio_irq_set_type,
 };
 
-static int ixp4xx_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                            unsigned int child,
+                                            unsigned int child_type,
+                                            unsigned int *parent,
+                                            unsigned int *parent_type)
 {
-       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
-       struct irq_fwspec fwspec;
-
-       fwspec.fwnode = g->fwnode;
-       fwspec.param_count = 2;
-       fwspec.param[0] = offset;
-       fwspec.param[1] = IRQ_TYPE_NONE;
-
-       return irq_create_fwspec_mapping(&fwspec);
-}
+       /* All these interrupts are level high in the CPU */
+       *parent_type = IRQ_TYPE_LEVEL_HIGH;
 
-static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
-                                           struct irq_fwspec *fwspec,
-                                           unsigned long *hwirq,
-                                           unsigned int *type)
-{
-       int ret;
-
-       /* We support standard DT translation */
-       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
-               return irq_domain_translate_twocell(domain, fwspec,
-                                                   hwirq, type);
+       /* GPIO lines 0..12 have dedicated IRQs */
+       if (child == 0) {
+               *parent = 6;
+               return 0;
        }
-
-       /* This goes away when we transition to DT */
-       if (is_fwnode_irqchip(fwspec->fwnode)) {
-               ret = irq_domain_translate_twocell(domain, fwspec,
-                                                  hwirq, type);
-               if (ret)
-                       return ret;
-               WARN_ON(*type == IRQ_TYPE_NONE);
+       if (child == 1) {
+               *parent = 7;
                return 0;
        }
-       return -EINVAL;
-}
-
-static int ixp4xx_gpio_irq_domain_alloc(struct irq_domain *d,
-                                       unsigned int irq, unsigned int nr_irqs,
-                                       void *data)
-{
-       struct ixp4xx_gpio *g = d->host_data;
-       irq_hw_number_t hwirq;
-       unsigned int type = IRQ_TYPE_NONE;
-       struct irq_fwspec *fwspec = data;
-       int ret;
-       int i;
-
-       ret = ixp4xx_gpio_irq_domain_translate(d, fwspec, &hwirq, &type);
-       if (ret)
-               return ret;
-
-       dev_dbg(g->dev, "allocate IRQ %d..%d, hwirq %lu..%lu\n",
-               irq, irq + nr_irqs - 1,
-               hwirq, hwirq + nr_irqs - 1);
-
-       for (i = 0; i < nr_irqs; i++) {
-               struct irq_fwspec parent_fwspec;
-               const struct ixp4xx_gpio_map *map;
-               int j;
-
-               /* Not all lines support IRQs */
-               for (j = 0; j < ARRAY_SIZE(ixp4xx_gpiomap); j++) {
-                       map = &ixp4xx_gpiomap[j];
-                       if (map->gpio_offset == hwirq)
-                               break;
-               }
-               if (j == ARRAY_SIZE(ixp4xx_gpiomap)) {
-                       dev_err(g->dev, "can't look up hwirq %lu\n", hwirq);
-                       return -EINVAL;
-               }
-               dev_dbg(g->dev, "found parent hwirq %u\n", map->parent_hwirq);
-
-               /*
-                * We set handle_bad_irq because the .set_type() should
-                * always be invoked and set the right type of handler.
-                */
-               irq_domain_set_info(d,
-                                   irq + i,
-                                   hwirq + i,
-                                   &ixp4xx_gpio_irqchip,
-                                   g,
-                                   handle_bad_irq,
-                                   NULL, NULL);
-               irq_set_probe(irq + i);
-
-               /*
-                * Create a IRQ fwspec to send up to the parent irqdomain:
-                * specify the hwirq we address on the parent and tie it
-                * all together up the chain.
-                */
-               parent_fwspec.fwnode = d->parent->fwnode;
-               parent_fwspec.param_count = 2;
-               parent_fwspec.param[0] = map->parent_hwirq;
-               /* This parent only handles asserted level IRQs */
-               parent_fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
-               dev_dbg(g->dev, "alloc_irqs_parent for %d parent hwirq %d\n",
-                       irq + i, map->parent_hwirq);
-               ret = irq_domain_alloc_irqs_parent(d, irq + i, 1,
-                                                  &parent_fwspec);
-               if (ret)
-                       dev_err(g->dev,
-                               "failed to allocate parent hwirq %d for hwirq %lu\n",
-                               map->parent_hwirq, hwirq);
+       if (child >= 2 && child <= 12) {
+               *parent = child + 17;
+               return 0;
        }
-
-       return 0;
+       return -EINVAL;
 }
 
-static const struct irq_domain_ops ixp4xx_gpio_irqdomain_ops = {
-       .translate = ixp4xx_gpio_irq_domain_translate,
-       .alloc = ixp4xx_gpio_irq_domain_alloc,
-       .free = irq_domain_free_irqs_common,
-};
-
 static int ixp4xx_gpio_probe(struct platform_device *pdev)
 {
        unsigned long flags;
@@ -311,8 +194,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
        struct irq_domain *parent;
        struct resource *res;
        struct ixp4xx_gpio *g;
+       struct gpio_irq_chip *girq;
        int ret;
-       int i;
 
        g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
        if (!g)
@@ -321,9 +204,36 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        g->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(g->base)) {
-               dev_err(dev, "ioremap error\n");
+       if (IS_ERR(g->base))
                return PTR_ERR(g->base);
+
+       /*
+        * When we convert to device tree we will simply look up the
+        * parent irqdomain using irq_find_host(parent) as parent comes
+        * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
+        * the fwnode. For now we need this boardfile style code.
+        */
+       if (np) {
+               struct device_node *irq_parent;
+
+               irq_parent = of_irq_find_parent(np);
+               if (!irq_parent) {
+                       dev_err(dev, "no IRQ parent node\n");
+                       return -ENODEV;
+               }
+               parent = irq_find_host(irq_parent);
+               if (!parent) {
+                       dev_err(dev, "no IRQ parent domain\n");
+                       return -ENODEV;
+               }
+               g->fwnode = of_node_to_fwnode(np);
+       } else {
+               parent = ixp4xx_get_irq_domain();
+               g->fwnode = irq_domain_alloc_fwnode(&res->start);
+               if (!g->fwnode) {
+                       dev_err(dev, "no domain base\n");
+                       return -ENODEV;
+               }
        }
 
        /*
@@ -360,7 +270,6 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
                dev_err(dev, "unable to init generic GPIO\n");
                return ret;
        }
-       g->gc.to_irq = ixp4xx_gpio_to_irq;
        g->gc.ngpio = 16;
        g->gc.label = "IXP4XX_GPIO_CHIP";
        /*
@@ -372,86 +281,22 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
        g->gc.parent = &pdev->dev;
        g->gc.owner = THIS_MODULE;
 
+       girq = &g->gc.irq;
+       girq->chip = &ixp4xx_gpio_irqchip;
+       girq->fwnode = g->fwnode;
+       girq->parent_domain = parent;
+       girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq;
+       girq->handler = handle_bad_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
        ret = devm_gpiochip_add_data(dev, &g->gc, g);
        if (ret) {
                dev_err(dev, "failed to add SoC gpiochip\n");
                return ret;
        }
 
-       /*
-        * When we convert to device tree we will simply look up the
-        * parent irqdomain using irq_find_host(parent) as parent comes
-        * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
-        * the fwnode. For now we need this boardfile style code.
-        */
-       if (np) {
-               struct device_node *irq_parent;
-
-               irq_parent = of_irq_find_parent(np);
-               if (!irq_parent) {
-                       dev_err(dev, "no IRQ parent node\n");
-                       return -ENODEV;
-               }
-               parent = irq_find_host(irq_parent);
-               if (!parent) {
-                       dev_err(dev, "no IRQ parent domain\n");
-                       return -ENODEV;
-               }
-               g->fwnode = of_node_to_fwnode(np);
-       } else {
-               parent = ixp4xx_get_irq_domain();
-               g->fwnode = irq_domain_alloc_fwnode(g->base);
-               if (!g->fwnode) {
-                       dev_err(dev, "no domain base\n");
-                       return -ENODEV;
-               }
-       }
-       g->domain = irq_domain_create_hierarchy(parent,
-                                               IRQ_DOMAIN_FLAG_HIERARCHY,
-                                               ARRAY_SIZE(ixp4xx_gpiomap),
-                                               g->fwnode,
-                                               &ixp4xx_gpio_irqdomain_ops,
-                                               g);
-       if (!g->domain) {
-               irq_domain_free_fwnode(g->fwnode);
-               dev_err(dev, "no hierarchical irq domain\n");
-               return ret;
-       }
-
-       /*
-        * After adding OF support, this is no longer needed: irqs
-        * will be allocated for the respective fwnodes.
-        */
-       if (!np) {
-               for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) {
-                       const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i];
-                       struct irq_fwspec fwspec;
-
-                       fwspec.fwnode = g->fwnode;
-                       /* This is the hwirq for the GPIO line side of things */
-                       fwspec.param[0] = map->gpio_offset;
-                       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
-                       fwspec.param_count = 2;
-                       ret = __irq_domain_alloc_irqs(g->domain,
-                                                     -1, /* just pick something */
-                                                     1,
-                                                     NUMA_NO_NODE,
-                                                     &fwspec,
-                                                     false,
-                                                     NULL);
-                       if (ret < 0) {
-                               irq_domain_free_fwnode(g->fwnode);
-                               dev_err(dev,
-                                       "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
-                                       map->gpio_offset, map->parent_hwirq,
-                                       ret);
-                               return ret;
-                       }
-               }
-       }
-
        platform_set_drvdata(pdev, g);
-       dev_info(dev, "IXP4 GPIO @%p registered\n", g->base);
+       dev_info(dev, "IXP4 GPIO registered\n");
 
        return 0;
 }
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
deleted file mode 100644 (file)
index a0f87c1..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * arch/arm/mach-ks8695/gpio.c
- *
- * Copyright (C) 2006 Andrew Victor
- * Updated to GPIOLIB, Copyright 2008 Simtec Electronics
- *                     Daniel Silverstone <dsilvers@simtec.co.uk>
- */
-#include <linux/gpio/driver.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/mach/irq.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/gpio-ks8695.h>
-
-/*
- * Configure a GPIO line for either GPIO function, or its internal
- * function (Interrupt, Timer, etc).
- */
-static void ks8695_gpio_mode(unsigned int pin, short gpio)
-{
-       unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_5)        /* only GPIO 0..5 have internal functions */
-               return;
-
-       local_irq_save(flags);
-
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
-       if (gpio)                       /* GPIO: set bit to 0 */
-               x &= ~enable[pin];
-       else                            /* Internal function: set bit to 1 */
-               x |= enable[pin];
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
-
-       local_irq_restore(flags);
-}
-
-
-static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
-
-/*
- * Configure GPIO pin as external interrupt source.
- */
-int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
-               return -EINVAL;
-
-       local_irq_save(flags);
-
-       /* set pin as input */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x &= ~IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       /* Set IRQ triggering type */
-       irq_set_irq_type(gpio_irq[pin], type);
-
-       /* enable interrupt mode */
-       ks8695_gpio_mode(pin, 0);
-
-       return 0;
-}
-EXPORT_SYMBOL(ks8695_gpio_interrupt);
-
-
-
-/* .... Generic GPIO interface .............................................. */
-
-/*
- * Configure the GPIO line as an input.
- */
-static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       /* set pin to GPIO mode */
-       ks8695_gpio_mode(pin, 1);
-
-       local_irq_save(flags);
-
-       /* set pin as input */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x &= ~IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-
-/*
- * Configure the GPIO line as an output, with default state.
- */
-static int ks8695_gpio_direction_output(struct gpio_chip *gc,
-                                       unsigned int pin, int state)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       /* set pin to GPIO mode */
-       ks8695_gpio_mode(pin, 1);
-
-       local_irq_save(flags);
-
-       /* set line state */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       if (state)
-               x |= IOPD(pin);
-       else
-               x &= ~IOPD(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
-
-       /* set pin as output */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x |= IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-
-/*
- * Set the state of an output GPIO line.
- */
-static void ks8695_gpio_set_value(struct gpio_chip *gc,
-                                 unsigned int pin, int state)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return;
-
-       local_irq_save(flags);
-
-       /* set output line state */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       if (state)
-               x |= IOPD(pin);
-       else
-               x &= ~IOPD(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
-
-       local_irq_restore(flags);
-}
-
-
-/*
- * Read the state of a GPIO line.
- */
-static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
-{
-       unsigned long x;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       return (x & IOPD(pin)) != 0;
-}
-
-
-/*
- * Map GPIO line to IRQ number.
- */
-static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
-{
-       if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
-               return -EINVAL;
-
-       return gpio_irq[pin];
-}
-
-/* GPIOLIB interface */
-
-static struct gpio_chip ks8695_gpio_chip = {
-       .label                  = "KS8695",
-       .direction_input        = ks8695_gpio_direction_input,
-       .direction_output       = ks8695_gpio_direction_output,
-       .get                    = ks8695_gpio_get_value,
-       .set                    = ks8695_gpio_set_value,
-       .to_irq                 = ks8695_gpio_to_irq,
-       .base                   = 0,
-       .ngpio                  = 16,
-       .can_sleep              = false,
-};
-
-/* Register the GPIOs */
-void ks8695_register_gpios(void)
-{
-       if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
-               printk(KERN_ERR "Unable to register core GPIOs\n");
-}
-
-/* .... Debug interface ..................................................... */
-
-#ifdef CONFIG_DEBUG_FS
-
-static int ks8695_gpio_show(struct seq_file *s, void *unused)
-{
-       unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
-       unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
-       unsigned long mode, ctrl, data;
-       int i;
-
-       mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
-       data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-
-       seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
-
-       for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
-               seq_printf(s, "%i:\t", i);
-
-               seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
-
-               if (i <= KS8695_GPIO_3) {
-                       if (ctrl & enable[i]) {
-                               seq_printf(s, "EXT%i ", i);
-
-                               switch ((ctrl & intmask[i]) >> (4 * i)) {
-                               case IOPC_TM_LOW:
-                                       seq_printf(s, "(Low)");         break;
-                               case IOPC_TM_HIGH:
-                                       seq_printf(s, "(High)");        break;
-                               case IOPC_TM_RISING:
-                                       seq_printf(s, "(Rising)");      break;
-                               case IOPC_TM_FALLING:
-                                       seq_printf(s, "(Falling)");     break;
-                               case IOPC_TM_EDGE:
-                                       seq_printf(s, "(Edges)");       break;
-                               }
-                       } else
-                               seq_printf(s, "GPIO\t");
-               } else if (i <= KS8695_GPIO_5) {
-                       if (ctrl & enable[i])
-                               seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
-                       else
-                               seq_printf(s, "GPIO\t");
-               } else {
-                       seq_printf(s, "GPIO\t");
-               }
-
-               seq_printf(s, "\t");
-
-               seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
-       }
-       return 0;
-}
-
-DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
-
-static int __init ks8695_gpio_debugfs_init(void)
-{
-       /* /sys/kernel/debug/ks8695_gpio */
-       debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
-                               &ks8695_gpio_fops);
-       return 0;
-}
-postcore_initcall(ks8695_gpio_debugfs_init);
-
-#endif
index 31b4a09..6bb9741 100644 (file)
@@ -358,25 +358,30 @@ static int lp_gpio_probe(struct platform_device *pdev)
        gc->can_sleep = false;
        gc->parent = dev;
 
-       ret = devm_gpiochip_add_data(dev, gc, lg);
-       if (ret) {
-               dev_err(dev, "failed adding lp-gpio chip\n");
-               return ret;
-       }
-
        /* set up interrupts  */
        if (irq_rc && irq_rc->start) {
+               struct gpio_irq_chip *girq;
+
+               girq = &gc->irq;
+               girq->chip = &lp_irqchip;
+               girq->parent_handler = lp_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = (unsigned)irq_rc->start;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_simple_irq;
+
                lp_gpio_irq_init_hw(lg);
-               ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0,
-                                          handle_simple_irq, IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(dev, "failed to add irqchip\n");
-                       return ret;
-               }
+       }
 
-               gpiochip_set_chained_irqchip(gc, &lp_irqchip,
-                                            (unsigned)irq_rc->start,
-                                            lp_gpio_irq_handler);
+       ret = devm_gpiochip_add_data(dev, gc, lg);
+       if (ret) {
+               dev_err(dev, "failed adding lp-gpio chip\n");
+               return ret;
        }
 
        pm_runtime_enable(dev);
index 4dbc837..7086f8b 100644 (file)
@@ -120,7 +120,7 @@ static const struct gpio_chip madera_gpio_chip = {
 static int madera_gpio_probe(struct platform_device *pdev)
 {
        struct madera *madera = dev_get_drvdata(pdev->dev.parent);
-       struct madera_pdata *pdata = dev_get_platdata(madera->dev);
+       struct madera_pdata *pdata = &madera->pdata;
        struct madera_gpio *madera_gpio;
        int ret;
 
@@ -136,6 +136,9 @@ static int madera_gpio_probe(struct platform_device *pdev)
        madera_gpio->gpio_chip.parent = pdev->dev.parent;
 
        switch (madera->type) {
+       case CS47L15:
+               madera_gpio->gpio_chip.ngpio = CS47L15_NUM_GPIOS;
+               break;
        case CS47L35:
                madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS;
                break;
@@ -147,13 +150,18 @@ static int madera_gpio_probe(struct platform_device *pdev)
        case CS47L91:
                madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS;
                break;
+       case CS42L92:
+       case CS47L92:
+       case CS47L93:
+               madera_gpio->gpio_chip.ngpio = CS47L92_NUM_GPIOS;
+               break;
        default:
                dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type);
                return -EINVAL;
        }
 
        /* We want to be usable on systems that don't use devicetree or acpi */
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                madera_gpio->gpio_chip.base = pdata->gpio_base;
        else
                madera_gpio->gpio_chip.base = -1;
index b7d89e3..47d05e3 100644 (file)
@@ -270,10 +270,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
        int ret;
 
        gpio_irq = platform_get_irq(pdev, 0);
-       if (gpio_irq <= 0) {
-               dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq);
+       if (gpio_irq <= 0)
                return -ENODEV;
-       }
 
        mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
        if (!mgpio)
index 3f03f4e..3075f25 100644 (file)
@@ -188,3 +188,4 @@ module_platform_driver(max77650_gpio_driver);
 MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-gpio");
index 8f46699..501e895 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 /*
  * Only first 8bits of a register correspond to each pin,
index 3302125..4f27ddf 100644 (file)
@@ -397,6 +397,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
 {
        const struct mrfld_gpio_pinrange *range;
        const char *pinctrl_dev_name;
+       struct gpio_irq_chip *girq;
        struct mrfld_gpio *priv;
        u32 gpio_base, irq_base;
        void __iomem *base;
@@ -444,6 +445,21 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
 
        raw_spin_lock_init(&priv->lock);
 
+       girq = &priv->chip.irq;
+       girq->chip = &mrfld_irqchip;
+       girq->parent_handler = mrfld_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = pdev->irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_bad_irq;
+
+       mrfld_irq_init_hw(priv);
+
        pci_set_drvdata(pdev, priv);
        retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
        if (retval) {
@@ -465,18 +481,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
                }
        }
 
-       retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base,
-                                     handle_bad_irq, IRQ_TYPE_NONE);
-       if (retval) {
-               dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n");
-               return retval;
-       }
-
-       mrfld_irq_init_hw(priv);
-
-       gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq,
-                                    mrfld_irq_handler);
-
        return 0;
 }
 
index f1a9c05..213aedc 100644 (file)
@@ -309,6 +309,7 @@ static const struct file_operations gpio_mockup_debugfs_ops = {
        .read = gpio_mockup_debugfs_read,
        .write = gpio_mockup_debugfs_write,
        .llseek = no_llseek,
+       .release = single_release,
 };
 
 static void gpio_mockup_debugfs_setup(struct device *dev,
index c8673a5..16a47de 100644 (file)
@@ -32,6 +32,7 @@
 #define GPIO_IMR               0x10
 #define GPIO_ICR               0x14
 #define GPIO_ICR2              0x18
+#define GPIO_IBE               0x18
 
 struct mpc8xxx_gpio_chip {
        struct gpio_chip        gc;
@@ -45,6 +46,27 @@ struct mpc8xxx_gpio_chip {
        unsigned int irqn;
 };
 
+/* The GPIO Input Buffer Enable register(GPIO_IBE) is used to
+ * control the input enable of each individual GPIO port.
+ * When an individual GPIO port’s direction is set to
+ * input (GPIO_GPDIR[DRn=0]), the associated input enable must be
+ * set (GPIOxGPIE[IEn]=1) to propagate the port value to the GPIO
+ * Data Register.
+ */
+static int ls1028a_gpio_dir_in_init(struct gpio_chip *gc)
+{
+       unsigned long flags;
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
+
+       spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+       gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
+
+       spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+
+       return 0;
+}
+
 /*
  * This hardware has a big endian bit assignment such that GPIO line 0 is
  * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
@@ -261,6 +283,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
 };
 
 struct mpc8xxx_gpio_devtype {
+       int (*gpio_dir_in_init)(struct gpio_chip *chip);
        int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int);
        int (*gpio_get)(struct gpio_chip *, unsigned int);
        int (*irq_set_type)(struct irq_data *, unsigned int);
@@ -271,6 +294,10 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = {
        .irq_set_type = mpc512x_irq_set_type,
 };
 
+static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = {
+       .gpio_dir_in_init = ls1028a_gpio_dir_in_init,
+};
+
 static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
        .gpio_dir_out = mpc5125_gpio_dir_out,
        .irq_set_type = mpc512x_irq_set_type,
@@ -291,6 +318,8 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = {
        { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, },
        { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, },
        { .compatible = "fsl,pq3-gpio",     },
+       { .compatible = "fsl,ls1028a-gpio", .data = &ls1028a_gpio_devtype, },
+       { .compatible = "fsl,ls1088a-gpio", .data = &ls1028a_gpio_devtype, },
        { .compatible = "fsl,qoriq-gpio",   },
        {}
 };
@@ -376,6 +405,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
        /* ack and mask all irqs */
        gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
        gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
+       /* enable input buffer  */
+       if (devtype->gpio_dir_in_init)
+               devtype->gpio_dir_in_init(gc);
 
        irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
                                         mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
index 79654fb..d1d785f 100644 (file)
@@ -241,13 +241,6 @@ mediatek_gpio_bank_probe(struct device *dev,
        if (!rg->chip.label)
                return -ENOMEM;
 
-       ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
-       if (ret < 0) {
-               dev_err(dev, "Could not register gpio %d, ret=%d\n",
-                       rg->chip.ngpio, ret);
-               return ret;
-       }
-
        rg->irq_chip.name = dev_name(dev);
        rg->irq_chip.parent_device = dev;
        rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;
@@ -256,8 +249,10 @@ mediatek_gpio_bank_probe(struct device *dev,
        rg->irq_chip.irq_set_type = mediatek_gpio_irq_type;
 
        if (mtk->gpio_irq) {
+               struct gpio_irq_chip *girq;
+
                /*
-                * Manually request the irq here instead of passing
+                * Directly request the irq here instead of passing
                 * a flow-handler to gpiochip_set_chained_irqchip,
                 * because the irq is shared.
                 */
@@ -271,15 +266,21 @@ mediatek_gpio_bank_probe(struct device *dev,
                        return ret;
                }
 
-               ret = gpiochip_irqchip_add(&rg->chip, &rg->irq_chip,
-                                          0, handle_simple_irq, IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(dev, "failed to add gpiochip_irqchip\n");
-                       return ret;
-               }
+               girq = &rg->chip.irq;
+               girq->chip = &rg->irq_chip;
+               /* This will let us handle the parent IRQ in the driver */
+               girq->parent_handler = NULL;
+               girq->num_parents = 0;
+               girq->parents = NULL;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_simple_irq;
+       }
 
-               gpiochip_set_chained_irqchip(&rg->chip, &rg->irq_chip,
-                                            mtk->gpio_irq, NULL);
+       ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
+       if (ret < 0) {
+               dev_err(dev, "Could not register gpio %d, ret=%d\n",
+                       rg->chip.ngpio, ret);
+               return ret;
        }
 
        /* set polarity to low for all gpios */
index b281358..7907a87 100644 (file)
@@ -435,12 +435,9 @@ static int mxc_gpio_probe(struct platform_device *pdev)
                return port->irq;
 
        /* the controller clock is optional */
-       port->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(port->clk)) {
-               if (PTR_ERR(port->clk) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               port->clk = NULL;
-       }
+       port->clk = devm_clk_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(port->clk))
+               return PTR_ERR(port->clk);
 
        err = clk_prepare_enable(port->clk);
        if (err) {
index 378b206..de5d138 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/bits.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
@@ -28,9 +29,9 @@
 #define PCA953X_INVERT         0x02
 #define PCA953X_DIRECTION      0x03
 
-#define REG_ADDR_MASK          0x3f
-#define REG_ADDR_EXT           0x40
-#define REG_ADDR_AI            0x80
+#define REG_ADDR_MASK          GENMASK(5, 0)
+#define REG_ADDR_EXT           BIT(6)
+#define REG_ADDR_AI            BIT(7)
 
 #define PCA957X_IN             0x00
 #define PCA957X_INVRT          0x01
 #define PCAL6524_OUT_INDCONF   0x2c
 #define PCAL6524_DEBOUNCE      0x2d
 
-#define PCA_GPIO_MASK          0x00FF
+#define PCA_GPIO_MASK          GENMASK(7, 0)
 
-#define PCAL_GPIO_MASK         0x1f
-#define PCAL_PINCTRL_MASK      0x60
+#define PCAL_GPIO_MASK         GENMASK(4, 0)
+#define PCAL_PINCTRL_MASK      GENMASK(6, 5)
 
-#define PCA_INT                        0x0100
-#define PCA_PCAL               0x0200
+#define PCA_INT                        BIT(8)
+#define PCA_PCAL               BIT(9)
 #define PCA_LATCH_INT          (PCA_PCAL | PCA_INT)
-#define PCA953X_TYPE           0x1000
-#define PCA957X_TYPE           0x2000
-#define PCA_TYPE_MASK          0xF000
+#define PCA953X_TYPE           BIT(12)
+#define PCA957X_TYPE           BIT(13)
+#define PCA_TYPE_MASK          GENMASK(15, 12)
 
 #define PCA_CHIP_TYPE(x)       ((x) & PCA_TYPE_MASK)
 
@@ -565,7 +566,7 @@ static void pca953x_irq_mask(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
 
-       chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
+       chip->irq_mask[d->hwirq / BANK_SZ] &= ~BIT(d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
@@ -573,7 +574,7 @@ static void pca953x_irq_unmask(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
 
-       chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
+       chip->irq_mask[d->hwirq / BANK_SZ] |= BIT(d->hwirq % BANK_SZ);
 }
 
 static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -604,10 +605,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
        u8 new_irqs;
        int level, i;
        u8 invert_irq_mask[MAX_BANK];
-       int reg_direction[MAX_BANK];
+       u8 reg_direction[MAX_BANK];
 
-       regmap_bulk_read(chip->regmap, chip->regs->direction, reg_direction,
-                        NBANK(chip));
+       pca953x_read_regs(chip, chip->regs->direction, reg_direction);
 
        if (chip->driver_data & PCA_PCAL) {
                /* Enable latch on interrupt-enabled inputs */
@@ -641,7 +641,7 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        int bank_nb = d->hwirq / BANK_SZ;
-       u8 mask = 1 << (d->hwirq % BANK_SZ);
+       u8 mask = BIT(d->hwirq % BANK_SZ);
 
        if (!(type & IRQ_TYPE_EDGE_BOTH)) {
                dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -666,7 +666,7 @@ static void pca953x_irq_shutdown(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 mask = 1 << (d->hwirq % BANK_SZ);
+       u8 mask = BIT(d->hwirq % BANK_SZ);
 
        chip->irq_trig_raise[d->hwirq / BANK_SZ] &= ~mask;
        chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
@@ -679,7 +679,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
        bool pending_seen = false;
        bool trigger_seen = false;
        u8 trigger[MAX_BANK];
-       int reg_direction[MAX_BANK];
+       u8 reg_direction[MAX_BANK];
        int ret, i;
 
        if (chip->driver_data & PCA_PCAL) {
@@ -710,8 +710,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
                return false;
 
        /* Remove output pins from the equation */
-       regmap_bulk_read(chip->regmap, chip->regs->direction, reg_direction,
-                        NBANK(chip));
+       pca953x_read_regs(chip, chip->regs->direction, reg_direction);
        for (i = 0; i < NBANK(chip); i++)
                cur_stat[i] &= reg_direction[i];
 
@@ -768,7 +767,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 {
        struct i2c_client *client = chip->client;
        struct irq_chip *irq_chip = &chip->irq_chip;
-       int reg_direction[MAX_BANK];
+       u8 reg_direction[MAX_BANK];
        int ret, i;
 
        if (!client->irq)
@@ -789,8 +788,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
         * interrupt.  We have to rely on the previous read for
         * this purpose.
         */
-       regmap_bulk_read(chip->regmap, chip->regs->direction, reg_direction,
-                        NBANK(chip));
+       pca953x_read_regs(chip, chip->regs->direction, reg_direction);
        for (i = 0; i < NBANK(chip); i++)
                chip->irq_stat[i] &= reg_direction[i];
        mutex_init(&chip->irq_lock);
@@ -849,12 +847,12 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 
        ret = regcache_sync_region(chip->regmap, chip->regs->output,
                                   chip->regs->output + NBANK(chip));
-       if (ret != 0)
+       if (ret)
                goto out;
 
        ret = regcache_sync_region(chip->regmap, chip->regs->direction,
                                   chip->regs->direction + NBANK(chip));
-       if (ret != 0)
+       if (ret)
                goto out;
 
        /* set platform specific polarity inversion */
@@ -949,19 +947,15 @@ static int pca953x_probe(struct i2c_client *client,
        if (i2c_id) {
                chip->driver_data = i2c_id->driver_data;
        } else {
-               const struct acpi_device_id *acpi_id;
-               struct device *dev = &client->dev;
-
-               chip->driver_data = (uintptr_t)of_device_get_match_data(dev);
-               if (!chip->driver_data) {
-                       acpi_id = acpi_match_device(pca953x_acpi_ids, dev);
-                       if (!acpi_id) {
-                               ret = -ENODEV;
-                               goto err_exit;
-                       }
-
-                       chip->driver_data = acpi_id->driver_data;
+               const void *match;
+
+               match = device_get_match_data(&client->dev);
+               if (!match) {
+                       ret = -ENODEV;
+                       goto err_exit;
                }
+
+               chip->driver_data = (uintptr_t)match;
        }
 
        i2c_set_clientdata(client, chip);
@@ -1041,8 +1035,7 @@ static int pca953x_remove(struct i2c_client *client)
                ret = pdata->teardown(client, chip->gpio_chip.base,
                                chip->gpio_chip.ngpio, pdata->context);
                if (ret < 0)
-                       dev_err(&client->dev, "%s failed, %d\n",
-                                       "teardown", ret);
+                       dev_err(&client->dev, "teardown failed, %d\n", ret);
        } else {
                ret = 0;
        }
@@ -1064,14 +1057,14 @@ static int pca953x_regcache_sync(struct device *dev)
         */
        ret = regcache_sync_region(chip->regmap, chip->regs->direction,
                                   chip->regs->direction + NBANK(chip));
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
                return ret;
        }
 
        ret = regcache_sync_region(chip->regmap, chip->regs->output,
                                   chip->regs->output + NBANK(chip));
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
                return ret;
        }
@@ -1080,7 +1073,7 @@ static int pca953x_regcache_sync(struct device *dev)
        if (chip->driver_data & PCA_PCAL) {
                ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
                                           PCAL953X_IN_LATCH + NBANK(chip));
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to sync INT latch registers: %d\n",
                                ret);
                        return ret;
@@ -1088,7 +1081,7 @@ static int pca953x_regcache_sync(struct device *dev)
 
                ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
                                           PCAL953X_INT_MASK + NBANK(chip));
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to sync INT mask registers: %d\n",
                                ret);
                        return ret;
@@ -1120,7 +1113,7 @@ static int pca953x_resume(struct device *dev)
 
        if (!atomic_read(&chip->wakeup_path)) {
                ret = regulator_enable(chip->regulator);
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to enable regulator: %d\n", ret);
                        return 0;
                }
@@ -1133,7 +1126,7 @@ static int pca953x_resume(struct device *dev)
                return ret;
 
        ret = regcache_sync(chip->regmap);
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to restore register map: %d\n", ret);
                return ret;
        }
index 1d99293..3f3d9a9 100644 (file)
@@ -409,8 +409,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
 
 static int __maybe_unused pch_gpio_suspend(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct pch_gpio *chip = pci_get_drvdata(pdev);
+       struct pch_gpio *chip = dev_get_drvdata(dev);
        unsigned long flags;
 
        spin_lock_irqsave(&chip->spinlock, flags);
@@ -422,8 +421,7 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
 
 static int __maybe_unused pch_gpio_resume(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct pch_gpio *chip = pci_get_drvdata(pdev);
+       struct pch_gpio *chip = dev_get_drvdata(dev);
        unsigned long flags;
 
        spin_lock_irqsave(&chip->spinlock, flags);
index 24228cf..05000ca 100644 (file)
@@ -305,10 +305,8 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev)
        mutex_init(&pmic_eic->buslock);
 
        pmic_eic->irq = platform_get_irq(pdev, 0);
-       if (pmic_eic->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n");
+       if (pmic_eic->irq < 0)
                return pmic_eic->irq;
-       }
 
        pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pmic_eic->map)
index f5c8b3a..d7314d3 100644 (file)
@@ -226,10 +226,8 @@ static int sprd_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        sprd_gpio->irq = platform_get_irq(pdev, 0);
-       if (sprd_gpio->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n");
+       if (sprd_gpio->irq < 0)
                return sprd_gpio->irq;
-       }
 
        sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sprd_gpio->base))
index dbf9cbe..994d542 100644 (file)
@@ -429,6 +429,23 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
+static void stmpe_init_irq_valid_mask(struct gpio_chip *gc,
+                                     unsigned long *valid_mask,
+                                     unsigned int ngpios)
+{
+       struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
+       int i;
+
+       if (!stmpe_gpio->norequest_mask)
+               return;
+
+       /* Forbid unused lines to be mapped as IRQs */
+       for (i = 0; i < sizeof(u32); i++) {
+               if (stmpe_gpio->norequest_mask & BIT(i))
+                       clear_bit(i, valid_mask);
+       }
+}
+
 static int stmpe_gpio_probe(struct platform_device *pdev)
 {
        struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
@@ -454,14 +471,21 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
        stmpe_gpio->chip.parent = &pdev->dev;
        stmpe_gpio->chip.of_node = np;
        stmpe_gpio->chip.base = -1;
+       /*
+        * REVISIT: this makes sure the valid mask gets allocated and
+        * filled in when adding the gpio_chip, but the rest of the
+        * gpio_irqchip is still filled in using the old method
+        * in gpiochip_irqchip_add_nested() so clean this up once we
+        * get the gpio_irqchip to initialize while adding the
+        * gpio_chip also for threaded irqchips.
+        */
+       stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask;
 
        if (IS_ENABLED(CONFIG_DEBUG_FS))
                 stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
 
        of_property_read_u32(np, "st,norequest-mask",
                        &stmpe_gpio->norequest_mask);
-       if (stmpe_gpio->norequest_mask)
-               stmpe_gpio->chip.irq.need_valid_mask = true;
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
@@ -487,14 +511,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
                        goto out_disable;
                }
-               if (stmpe_gpio->norequest_mask) {
-                       int i;
-
-                       /* Forbid unused lines to be mapped as IRQs */
-                       for (i = 0; i < sizeof(u32); i++)
-                               if (stmpe_gpio->norequest_mask & BIT(i))
-                                       clear_bit(i, stmpe_gpio->chip.irq.valid_mask);
-               }
                ret =  gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
                                                   &stmpe_gpio_irq_chip,
                                                   0,
index bd1f3f7..5e37518 100644 (file)
@@ -171,10 +171,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
                struct irq_chip_generic *gc;
 
                ret = platform_get_irq(pdev, 0);
-               if (ret < 0) {
-                       dev_err(dev, "No interrupt specified.\n");
+               if (ret < 0)
                        return ret;
-               }
 
                tb10x_gpio->gc.to_irq   = tb10x_gpio_to_irq;
                tb10x_gpio->irq         = ret;
index 0f59161..8a01d36 100644 (file)
@@ -624,10 +624,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
        for (i = 0; i < tgi->bank_count; i++) {
                ret = platform_get_irq(pdev, i);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
+               if (ret < 0)
                        return ret;
-               }
 
                bank = &tgi->bank_info[i];
                bank->bank = i;
index 715371b..ddad5c7 100644 (file)
@@ -53,7 +53,6 @@ struct thunderx_line {
 struct thunderx_gpio {
        struct gpio_chip        chip;
        u8 __iomem              *register_base;
-       struct irq_domain       *irqd;
        struct msix_entry       *msix_entries;  /* per line MSI-X */
        struct thunderx_line    *line_entries;  /* per line irq info */
        raw_spinlock_t          lock;
@@ -283,54 +282,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip,
        }
 }
 
-static void thunderx_gpio_irq_ack(struct irq_data *data)
+static void thunderx_gpio_irq_ack(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_INTR,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_mask(struct irq_data *data)
+static void thunderx_gpio_irq_mask(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1C,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
+static void thunderx_gpio_irq_mask_ack(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_unmask(struct irq_data *data)
+static void thunderx_gpio_irq_unmask(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1S,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static int thunderx_gpio_irq_set_type(struct irq_data *data,
+static int thunderx_gpio_irq_set_type(struct irq_data *d,
                                      unsigned int flow_type)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+       struct thunderx_line *txline =
+               &txgpio->line_entries[irqd_to_hwirq(d)];
        u64 bit_cfg;
 
-       irqd_set_trigger_type(data, flow_type);
+       irqd_set_trigger_type(d, flow_type);
 
        bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN;
 
        if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-               irq_set_handler_locked(data, handle_fasteoi_ack_irq);
+               irq_set_handler_locked(d, handle_fasteoi_ack_irq);
                bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
        } else {
-               irq_set_handler_locked(data, handle_fasteoi_mask_irq);
+               irq_set_handler_locked(d, handle_fasteoi_mask_irq);
        }
 
        raw_spin_lock(&txgpio->lock);
@@ -359,33 +364,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data)
        irq_chip_disable_parent(data);
 }
 
-static int thunderx_gpio_irq_request_resources(struct irq_data *data)
-{
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
-       int r;
-
-       r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
-       if (r)
-               return r;
-
-       r = irq_chip_request_resources_parent(data);
-       if (r)
-               gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
-
-       return r;
-}
-
-static void thunderx_gpio_irq_release_resources(struct irq_data *data)
-{
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
-
-       irq_chip_release_resources_parent(data);
-
-       gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
-}
-
 /*
  * Interrupts are chained from underlying MSI-X vectors.  We have
  * these irq_chip functions to be able to handle level triggering
@@ -402,48 +380,22 @@ static struct irq_chip thunderx_gpio_irq_chip = {
        .irq_unmask             = thunderx_gpio_irq_unmask,
        .irq_eoi                = irq_chip_eoi_parent,
        .irq_set_affinity       = irq_chip_set_affinity_parent,
-       .irq_request_resources  = thunderx_gpio_irq_request_resources,
-       .irq_release_resources  = thunderx_gpio_irq_release_resources,
        .irq_set_type           = thunderx_gpio_irq_set_type,
 
        .flags                  = IRQCHIP_SET_TYPE_MASKED
 };
 
-static int thunderx_gpio_irq_translate(struct irq_domain *d,
-                                      struct irq_fwspec *fwspec,
-                                      irq_hw_number_t *hwirq,
-                                      unsigned int *type)
+static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                              unsigned int child,
+                                              unsigned int child_type,
+                                              unsigned int *parent,
+                                              unsigned int *parent_type)
 {
-       struct thunderx_gpio *txgpio = d->host_data;
-
-       if (WARN_ON(fwspec->param_count < 2))
-               return -EINVAL;
-       if (fwspec->param[0] >= txgpio->chip.ngpio)
-               return -EINVAL;
-       *hwirq = fwspec->param[0];
-       *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
-       return 0;
-}
-
-static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
-                                  unsigned int nr_irqs, void *arg)
-{
-       struct thunderx_line *txline = arg;
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
-       return irq_domain_set_hwirq_and_chip(d, virq, txline->line,
-                                            &thunderx_gpio_irq_chip, txline);
-}
-
-static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
-       .alloc          = thunderx_gpio_irq_alloc,
-       .translate      = thunderx_gpio_irq_translate
-};
-
-static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
-       struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
-
-       return irq_find_mapping(txgpio->irqd, offset);
+       *parent = txgpio->base_msi + (2 * child);
+       *parent_type = IRQ_TYPE_LEVEL_HIGH;
+       return 0;
 }
 
 static int thunderx_gpio_probe(struct pci_dev *pdev,
@@ -453,6 +405,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        struct device *dev = &pdev->dev;
        struct thunderx_gpio *txgpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        int ngpio, i;
        int err = 0;
 
@@ -497,8 +450,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        }
 
        txgpio->msix_entries = devm_kcalloc(dev,
-                                         ngpio, sizeof(struct msix_entry),
-                                         GFP_KERNEL);
+                                           ngpio, sizeof(struct msix_entry),
+                                           GFP_KERNEL);
        if (!txgpio->msix_entries) {
                err = -ENOMEM;
                goto out;
@@ -539,27 +492,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        if (err < 0)
                goto out;
 
-       /*
-        * Push GPIO specific irqdomain on hierarchy created as a side
-        * effect of the pci_enable_msix()
-        */
-       txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain,
-                                                  0, 0, of_node_to_fwnode(dev->of_node),
-                                                  &thunderx_gpio_irqd_ops, txgpio);
-       if (!txgpio->irqd) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       /* Push on irq_data and the domain for each line. */
-       for (i = 0; i < ngpio; i++) {
-               err = irq_domain_push_irq(txgpio->irqd,
-                                         txgpio->msix_entries[i].vector,
-                                         &txgpio->line_entries[i]);
-               if (err < 0)
-                       dev_err(dev, "irq_domain_push_irq: %d\n", err);
-       }
-
        chip->label = KBUILD_MODNAME;
        chip->parent = dev;
        chip->owner = THIS_MODULE;
@@ -574,11 +506,28 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        chip->set = thunderx_gpio_set;
        chip->set_multiple = thunderx_gpio_set_multiple;
        chip->set_config = thunderx_gpio_set_config;
-       chip->to_irq = thunderx_gpio_to_irq;
+       girq = &chip->irq;
+       girq->chip = &thunderx_gpio_irq_chip;
+       girq->fwnode = of_node_to_fwnode(dev->of_node);
+       girq->parent_domain =
+               irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
+       girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq;
+       girq->handler = handle_bad_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
        err = devm_gpiochip_add_data(dev, chip, txgpio);
        if (err)
                goto out;
 
+       /* Push on irq_data and the domain for each line. */
+       for (i = 0; i < ngpio; i++) {
+               err = irq_domain_push_irq(chip->irq.domain,
+                                         txgpio->msix_entries[i].vector,
+                                         chip);
+               if (err < 0)
+                       dev_err(dev, "irq_domain_push_irq: %d\n", err);
+       }
+
        dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
                 ngpio, chip->base);
        return 0;
@@ -593,10 +542,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev)
        struct thunderx_gpio *txgpio = pci_get_drvdata(pdev);
 
        for (i = 0; i < txgpio->chip.ngpio; i++)
-               irq_domain_pop_irq(txgpio->irqd,
+               irq_domain_pop_irq(txgpio->chip.irq.domain,
                                   txgpio->msix_entries[i].vector);
 
-       irq_domain_remove(txgpio->irqd);
+       irq_domain_remove(txgpio->chip.irq.domain);
 
        pci_set_drvdata(pdev, NULL);
 }
index d5880db..a3109bc 100644 (file)
@@ -214,11 +214,23 @@ static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = {
                           tqmx86_gpio_runtime_resume, NULL)
 };
 
+static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
+                                      unsigned long *valid_mask,
+                                      unsigned int ngpios)
+{
+       /* Only GPIOs 4-7 are valid for interrupts. Clear the others */
+       clear_bit(0, valid_mask);
+       clear_bit(1, valid_mask);
+       clear_bit(2, valid_mask);
+       clear_bit(3, valid_mask);
+}
+
 static int tqmx86_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct tqmx86_gpio_data *gpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        void __iomem *io_base;
        struct resource *res;
        int ret, irq;
@@ -259,17 +271,10 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
        chip->get = tqmx86_gpio_get;
        chip->set = tqmx86_gpio_set;
        chip->ngpio = TQMX86_NGPIO;
-       chip->irq.need_valid_mask = true;
        chip->parent = pdev->dev.parent;
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = devm_gpiochip_add_data(dev, chip, gpio);
-       if (ret) {
-               dev_err(dev, "Could not register GPIO chip\n");
-               goto out_pm_dis;
-       }
-
        if (irq) {
                struct irq_chip *irq_chip = &gpio->irq_chip;
                u8 irq_status;
@@ -287,23 +292,28 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
                irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);
                tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
 
-               ret = gpiochip_irqchip_add(chip, irq_chip,
-                                          0, handle_simple_irq,
-                                          IRQ_TYPE_EDGE_BOTH);
-               if (ret) {
-                       dev_err(dev, "Could not add irq chip\n");
+               girq = &chip->irq;
+               girq->chip = irq_chip;
+               girq->parent_handler = tqmx86_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents) {
+                       ret = -ENOMEM;
                        goto out_pm_dis;
                }
-
-               gpiochip_set_chained_irqchip(chip, irq_chip,
-                                            irq, tqmx86_gpio_irq_handler);
+               girq->parents[0] = irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_simple_irq;
+               girq->init_valid_mask = tqmx86_init_irq_valid_mask;
        }
 
-       /* Only GPIOs 4-7 are valid for interrupts. Clear the others */
-       clear_bit(0, chip->irq.valid_mask);
-       clear_bit(1, chip->irq.valid_mask);
-       clear_bit(2, chip->irq.valid_mask);
-       clear_bit(3, chip->irq.valid_mask);
+       ret = devm_gpiochip_add_data(dev, chip, gpio);
+       if (ret) {
+               dev_err(dev, "Could not register GPIO chip\n");
+               goto out_pm_dis;
+       }
 
        dev_info(dev, "GPIO functionality initialized with %d pins\n",
                 chip->ngpio);
index 7ba668d..58776f2 100644 (file)
@@ -243,6 +243,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        struct device_node *np = dev->of_node;
        struct vf610_gpio_port *port;
        struct gpio_chip *gc;
+       struct gpio_irq_chip *girq;
        struct irq_chip *ic;
        int i;
        int ret;
@@ -318,10 +319,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        ic->irq_set_type = vf610_gpio_irq_set_type;
        ic->irq_set_wake = vf610_gpio_irq_set_wake;
 
-       ret = devm_gpiochip_add_data(dev, gc, port);
-       if (ret < 0)
-               return ret;
-
        /* Mask all GPIO interrupts */
        for (i = 0; i < gc->ngpio; i++)
                vf610_gpio_writel(0, port->base + PORT_PCR(i));
@@ -329,15 +326,20 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        /* Clear the interrupt status register for all GPIO's */
        vf610_gpio_writel(~0, port->base + PORT_ISFR);
 
-       ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "failed to add irqchip\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(gc, ic, port->irq,
-                                    vf610_gpio_irq_handler);
+       girq = &gc->irq;
+       girq->chip = ic;
+       girq->parent_handler = vf610_gpio_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = port->irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_edge_irq;
 
-       return 0;
+       return devm_gpiochip_add_data(dev, gc, port);
 }
 
 static struct platform_driver vf610_gpio_driver = {
index 9b604f1..c301c1d 100644 (file)
@@ -79,7 +79,7 @@ MODULE_PARM_DESC(gpioa_freq,
 /* ----- begin of gipo a chip -------------------------------------------- */
 
 static int vprbrd_gpioa_get(struct gpio_chip *chip,
-               unsigned offset)
+               unsigned int offset)
 {
        int ret, answer, error = 0;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -129,7 +129,7 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip,
 }
 
 static void vprbrd_gpioa_set(struct gpio_chip *chip,
-               unsigned offset, int value)
+               unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -170,7 +170,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
-                       unsigned offset)
+                       unsigned int offset)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -207,7 +207,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
-                       unsigned offset, int value)
+                       unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -251,8 +251,8 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
 
 /* ----- begin of gipo b chip -------------------------------------------- */
 
-static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
-       unsigned dir)
+static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
+       unsigned int dir)
 {
        struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
        int ret;
@@ -273,7 +273,7 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
 }
 
 static int vprbrd_gpiob_get(struct gpio_chip *chip,
-               unsigned offset)
+               unsigned int offset)
 {
        int ret;
        u16 val;
@@ -305,7 +305,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip,
 }
 
 static void vprbrd_gpiob_set(struct gpio_chip *chip,
-               unsigned offset, int value)
+               unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -338,7 +338,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
-                       unsigned offset)
+                       unsigned int offset)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -359,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
-                       unsigned offset, int value)
+                       unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
index 38c0191..25d8644 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 /* Common property names */
 #define XGENE_NIRQ_PROPERTY            "apm,nr-irqs"
index 54d3359..d7b16bb 100644 (file)
@@ -290,6 +290,7 @@ MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
 static int xlp_gpio_probe(struct platform_device *pdev)
 {
        struct gpio_chip *gc;
+       struct gpio_irq_chip *girq;
        struct xlp_gpio_priv *priv;
        void __iomem *gpio_base;
        int irq_base, irq, err;
@@ -395,27 +396,27 @@ static int xlp_gpio_probe(struct platform_device *pdev)
                irq_base = 0;
        }
 
+       girq = &gc->irq;
+       girq->chip = &xlp_gpio_irq_chip;
+       girq->parent_handler = xlp_gpio_generic_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = irq;
+       girq->first = irq_base;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
+
        err = gpiochip_add_data(gc, priv);
        if (err < 0)
                return err;
 
-       err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
-                               handle_level_irq, IRQ_TYPE_NONE);
-       if (err) {
-               dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
-               goto out_gpio_remove;
-       }
-
-       gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq,
-                       xlp_gpio_generic_handler);
-
        dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
 
        return 0;
-
-out_gpio_remove:
-       gpiochip_remove(gc);
-       return err;
 }
 
 #ifdef CONFIG_ACPI
index 8637adb..98cbaf0 100644 (file)
@@ -215,6 +215,7 @@ static int zx_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct zx_gpio *chip;
+       struct gpio_irq_chip *girq;
        int irq, id, ret;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
@@ -242,32 +243,30 @@ static int zx_gpio_probe(struct platform_device *pdev)
        chip->gc.parent = dev;
        chip->gc.owner = THIS_MODULE;
 
-       ret = gpiochip_add_data(&chip->gc, chip);
-       if (ret)
-               return ret;
-
        /*
         * irq_chip support
         */
        writew_relaxed(0xffff, chip->base + ZX_GPIO_IM);
        writew_relaxed(0, chip->base + ZX_GPIO_IE);
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "invalid IRQ\n");
-               gpiochip_remove(&chip->gc);
-               return -ENODEV;
-       }
+       if (irq < 0)
+               return irq;
+       girq = &chip->gc.irq;
+       girq->chip = &zx_irqchip;
+       girq->parent_handler = zx_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_simple_irq;
 
-       ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip,
-                                  0, handle_simple_irq,
-                                  IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "could not add irqchip\n");
-               gpiochip_remove(&chip->gc);
+       ret = gpiochip_add_data(&chip->gc, chip);
+       if (ret)
                return ret;
-       }
-       gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip,
-                                    irq, zx_irq_handler);
 
        platform_set_drvdata(pdev, chip);
        dev_info(dev, "ZX GPIO chip registered\n");
index f241b6c..cd475ff 100644 (file)
@@ -830,6 +830,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        int ret, bank_num;
        struct zynq_gpio *gpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        const struct of_device_id *match;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -849,10 +850,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
                return PTR_ERR(gpio->base_addr);
 
        gpio->irq = platform_get_irq(pdev, 0);
-       if (gpio->irq < 0) {
-               dev_err(&pdev->dev, "invalid IRQ\n");
+       if (gpio->irq < 0)
                return gpio->irq;
-       }
 
        /* configure the gpio chip */
        chip = &gpio->chip;
@@ -887,34 +886,38 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_pm_dis;
 
-       /* report a bug if gpio chip registration fails */
-       ret = gpiochip_add_data(chip, gpio);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to add gpio chip\n");
-               goto err_pm_put;
-       }
-
        /* disable interrupts for all banks */
        for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
                writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
                               ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
 
-       ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0,
-                                  handle_level_irq, IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to add irq chip\n");
-               goto err_rm_gpiochip;
+       /* Set up the GPIO irqchip */
+       girq = &chip->irq;
+       girq->chip = &zynq_gpio_edge_irqchip;
+       girq->parent_handler = zynq_gpio_irqhandler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents) {
+               ret = -ENOMEM;
+               goto err_pm_put;
        }
+       girq->parents[0] = gpio->irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
 
-       gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
-                                    zynq_gpio_irqhandler);
+       /* report a bug if gpio chip registration fails */
+       ret = gpiochip_add_data(chip, gpio);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add gpio chip\n");
+               goto err_pm_put;
+       }
 
        pm_runtime_put(&pdev->dev);
 
        return 0;
 
-err_rm_gpiochip:
-       gpiochip_remove(chip);
 err_pm_put:
        pm_runtime_put(&pdev->dev);
 err_pm_dis:
index 39f2f90..609ed16 100644 (file)
@@ -7,6 +7,7 @@
  *          Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
+#include <linux/dmi.h>
 #include <linux/errno.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/pinctrl/pinctrl.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
+
+static int run_edge_events_on_boot = -1;
+module_param(run_edge_events_on_boot, int, 0444);
+MODULE_PARM_DESC(run_edge_events_on_boot,
+                "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
 
 /**
  * struct acpi_gpio_event - ACPI GPIO event handler data
@@ -170,10 +177,13 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
        event->irq_requested = true;
 
        /* Make sure we trigger the initial state of edge-triggered IRQs */
-       value = gpiod_get_raw_value_cansleep(event->desc);
-       if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
-           ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
-               event->handler(event->irq, event);
+       if (run_edge_events_on_boot &&
+           (event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
+               value = gpiod_get_raw_value_cansleep(event->desc);
+               if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
+                   ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
+                       event->handler(event->irq, event);
+       }
 }
 
 static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
@@ -382,6 +392,13 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev,
 }
 EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
 
+void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
+       if (adev)
+               adev->driver_gpios = NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios);
+
 static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res)
 {
        acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev));
@@ -720,6 +737,16 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
        return ret ? ERR_PTR(ret) : lookup.desc;
 }
 
+static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
+                                    const char *con_id)
+{
+       /* Never allow fallback if the device has properties */
+       if (acpi_dev_has_props(adev) || adev->driver_gpios)
+               return false;
+
+       return con_id == NULL;
+}
+
 struct gpio_desc *acpi_find_gpio(struct device *dev,
                                 const char *con_id,
                                 unsigned int idx,
@@ -1256,15 +1283,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
        return count ? count : -ENOENT;
 }
 
-bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
-{
-       /* Never allow fallback if the device has properties */
-       if (acpi_dev_has_props(adev) || adev->driver_gpios)
-               return false;
-
-       return con_id == NULL;
-}
-
 /* Run deferred acpi_gpiochip_request_irqs() */
 static int acpi_gpio_handle_deferred_request_irqs(void)
 {
@@ -1283,3 +1301,28 @@ static int acpi_gpio_handle_deferred_request_irqs(void)
 }
 /* We must use _sync so that this runs after the first deferred_probe run */
 late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
+
+static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
+               }
+       },
+       {} /* Terminating entry */
+};
+
+static int acpi_gpio_setup_params(void)
+{
+       if (run_edge_events_on_boot < 0) {
+               if (dmi_check_system(run_edge_events_on_boot_blacklist))
+                       run_edge_events_on_boot = 0;
+               else
+                       run_edge_events_on_boot = 1;
+       }
+
+       return 0;
+}
+
+/* Directly after dmi_setup() which runs as core_initcall() */
+postcore_initcall(acpi_gpio_setup_params);
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
new file mode 100644 (file)
index 0000000..1c6d65c
--- /dev/null
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012,2019 Intel Corporation
+ */
+
+#ifndef GPIOLIB_ACPI_H
+#define GPIOLIB_ACPI_H
+
+struct acpi_device;
+
+/**
+ * struct acpi_gpio_info - ACPI GPIO specific information
+ * @adev: reference to ACPI device which consumes GPIO resource
+ * @flags: GPIO initialization flags
+ * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
+ * @pin_config: pin bias as provided by ACPI
+ * @polarity: interrupt polarity as provided by ACPI
+ * @triggering: triggering type as provided by ACPI
+ * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
+ */
+struct acpi_gpio_info {
+       struct acpi_device *adev;
+       enum gpiod_flags flags;
+       bool gpioint;
+       int pin_config;
+       int polarity;
+       int triggering;
+       unsigned int quirks;
+};
+
+#ifdef CONFIG_ACPI
+void acpi_gpiochip_add(struct gpio_chip *chip);
+void acpi_gpiochip_remove(struct gpio_chip *chip);
+
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
+
+int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
+                                struct acpi_gpio_info *info);
+int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                       struct acpi_gpio_info *info);
+
+struct gpio_desc *acpi_find_gpio(struct device *dev,
+                                const char *con_id,
+                                unsigned int idx,
+                                enum gpiod_flags *dflags,
+                                unsigned long *lookupflags);
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info);
+
+int acpi_gpio_count(struct device *dev, const char *con_id);
+#else
+static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
+static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
+
+static inline void
+acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
+
+static inline void
+acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
+
+static inline int
+acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
+{
+       return 0;
+}
+static inline int
+acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                   struct acpi_gpio_info *info)
+{
+       return 0;
+}
+
+static inline struct gpio_desc *
+acpi_find_gpio(struct device *dev, const char *con_id,
+              unsigned int idx, enum gpiod_flags *dflags,
+              unsigned long *lookupflags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline struct gpio_desc *
+acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
+                   int index, struct acpi_gpio_info *info)
+{
+       return ERR_PTR(-ENXIO);
+}
+static inline int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+       return -ENODEV;
+}
+#endif
+
+#endif /* GPIOLIB_ACPI_H */
index 0acc2cc..98e3c20 100644 (file)
@@ -59,7 +59,7 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
 {
        return devm_gpiod_get_index(dev, con_id, 0, flags);
 }
-EXPORT_SYMBOL(devm_gpiod_get);
+EXPORT_SYMBOL_GPL(devm_gpiod_get);
 
 /**
  * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
@@ -77,7 +77,7 @@ struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
 {
        return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
 }
-EXPORT_SYMBOL(devm_gpiod_get_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_optional);
 
 /**
  * devm_gpiod_get_index - Resource-managed gpiod_get_index()
@@ -127,7 +127,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
 
        return desc;
 }
-EXPORT_SYMBOL(devm_gpiod_get_index);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
 
 /**
  * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
@@ -182,7 +182,7 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
 
        return desc;
 }
-EXPORT_SYMBOL(devm_gpiod_get_from_of_node);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
 
 /**
  * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
@@ -239,7 +239,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
 
        return desc;
 }
-EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);
+EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child);
 
 /**
  * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
@@ -268,7 +268,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
 
        return desc;
 }
-EXPORT_SYMBOL(devm_gpiod_get_index_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional);
 
 /**
  * devm_gpiod_get_array - Resource-managed gpiod_get_array()
@@ -303,7 +303,7 @@ struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
 
        return descs;
 }
-EXPORT_SYMBOL(devm_gpiod_get_array);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_array);
 
 /**
  * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
@@ -328,7 +328,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
 
        return descs;
 }
-EXPORT_SYMBOL(devm_gpiod_get_array_optional);
+EXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional);
 
 /**
  * devm_gpiod_put - Resource-managed gpiod_put()
@@ -344,7 +344,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
        WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
                &desc));
 }
-EXPORT_SYMBOL(devm_gpiod_put);
+EXPORT_SYMBOL_GPL(devm_gpiod_put);
 
 /**
  * devm_gpiod_unhinge - Remove resource management from a gpio descriptor
@@ -374,7 +374,7 @@ void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
        /* Anything else we should warn about */
        WARN_ON(ret);
 }
-EXPORT_SYMBOL(devm_gpiod_unhinge);
+EXPORT_SYMBOL_GPL(devm_gpiod_unhinge);
 
 /**
  * devm_gpiod_put_array - Resource-managed gpiod_put_array()
@@ -390,7 +390,7 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
        WARN_ON(devres_release(dev, devm_gpiod_release_array,
                               devm_gpiod_match_array, &descs));
 }
-EXPORT_SYMBOL(devm_gpiod_put_array);
+EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
 
 
 
@@ -444,7 +444,7 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
 
        return 0;
 }
-EXPORT_SYMBOL(devm_gpio_request);
+EXPORT_SYMBOL_GPL(devm_gpio_request);
 
 /**
  *     devm_gpio_request_one - request a single GPIO with initial setup
@@ -474,7 +474,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
 
        return 0;
 }
-EXPORT_SYMBOL(devm_gpio_request_one);
+EXPORT_SYMBOL_GPL(devm_gpio_request_one);
 
 /**
  *      devm_gpio_free - free a GPIO
@@ -492,4 +492,4 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
        WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
                &gpio));
 }
-EXPORT_SYMBOL(devm_gpio_free);
+EXPORT_SYMBOL_GPL(devm_gpio_free);
index 567fb98..1eea2c6 100644 (file)
 #include <linux/gpio/machine.h>
 
 #include "gpiolib.h"
+#include "gpiolib-of.h"
+
+/*
+ * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
+ *
+ * FIXME: get rid of those external users by converting them to GPIO
+ * descriptors and let them all use gpiod_get_count()
+ */
+int of_gpio_get_count(struct device *dev, const char *con_id)
+{
+       int ret;
+       char propname[32];
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id)
+                       snprintf(propname, sizeof(propname), "%s-%s",
+                                con_id, gpio_suffixes[i]);
+               else
+                       snprintf(propname, sizeof(propname), "%s",
+                                gpio_suffixes[i]);
+
+               ret = of_gpio_named_count(dev->of_node, propname);
+               if (ret > 0)
+                       break;
+       }
+       return ret ? ret : -ENOENT;
+}
 
 static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
 {
@@ -53,6 +81,23 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
        return gpiochip_get_desc(chip, ret);
 }
 
+/**
+ * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
+ * to set the .valid_mask
+ * @dev: the device for the GPIO provider
+ * @return: true if the valid mask needs to be set
+ */
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
+{
+       int size;
+       struct device_node *np = gc->of_node;
+
+       size = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
+       if (size > 0 && size % 2 == 0)
+               return true;
+       return false;
+}
+
 static void of_gpio_flags_quirks(struct device_node *np,
                                 const char *propname,
                                 enum of_gpio_flags *flags,
@@ -178,7 +223,7 @@ static void of_gpio_flags_quirks(struct device_node *np,
  * value on the error condition. If @flags is not NULL the function also fills
  * in flags for the GPIO.
  */
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+static struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
                     const char *propname, int index, enum of_gpio_flags *flags)
 {
        struct of_phandle_args gpiospec;
@@ -229,7 +274,76 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
        else
                return desc_to_gpio(desc);
 }
-EXPORT_SYMBOL(of_get_named_gpio_flags);
+EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
+
+/**
+ * gpiod_get_from_of_node() - obtain a GPIO from an OF node
+ * @node:      handle of the OF node
+ * @propname:  name of the DT property representing the GPIO
+ * @index:     index of the GPIO to obtain for the consumer
+ * @dflags:    GPIO initialization flags
+ * @label:     label to attach to the requested GPIO
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @dflags.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label)
+{
+       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
+       struct gpio_desc *desc;
+       enum of_gpio_flags flags;
+       bool active_low = false;
+       bool single_ended = false;
+       bool open_drain = false;
+       bool transitory = false;
+       int ret;
+
+       desc = of_get_named_gpiod_flags(node, propname,
+                                       index, &flags);
+
+       if (!desc || IS_ERR(desc)) {
+               return desc;
+       }
+
+       active_low = flags & OF_GPIO_ACTIVE_LOW;
+       single_ended = flags & OF_GPIO_SINGLE_ENDED;
+       open_drain = flags & OF_GPIO_OPEN_DRAIN;
+       transitory = flags & OF_GPIO_TRANSITORY;
+
+       ret = gpiod_request(desc, label);
+       if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
+               return desc;
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (active_low)
+               lflags |= GPIO_ACTIVE_LOW;
+
+       if (single_ended) {
+               if (open_drain)
+                       lflags |= GPIO_OPEN_DRAIN;
+               else
+                       lflags |= GPIO_OPEN_SOURCE;
+       }
+
+       if (transitory)
+               lflags |= GPIO_TRANSITORY;
+
+       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       if (ret < 0) {
+               gpiod_put(desc);
+               return ERR_PTR(ret);
+       }
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
 
 /*
  * The SPI GPIO bindings happened before we managed to establish that GPIO
@@ -324,6 +438,19 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
        return desc;
 }
 
+static struct gpio_desc *of_find_arizona_gpio(struct device *dev,
+                                             const char *con_id,
+                                             enum of_gpio_flags *of_flags)
+{
+       if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
+               return ERR_PTR(-ENOENT);
+
+       if (!con_id || strcmp(con_id, "wlf,reset"))
+               return ERR_PTR(-ENOENT);
+
+       return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags);
+}
+
 struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
                               unsigned int idx, unsigned long *flags)
 {
@@ -343,36 +470,30 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
 
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
-               /*
-                * -EPROBE_DEFER in our case means that we found a
-                * valid GPIO property, but no controller has been
-                * registered so far.
-                *
-                * This means we don't need to look any further for
-                * alternate name conventions, and we should really
-                * preserve the return code for our user to be able to
-                * retry probing later.
-                */
-               if (IS_ERR(desc) && PTR_ERR(desc) == -EPROBE_DEFER)
-                       return desc;
 
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+               if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT)
                        break;
        }
 
-       /* Special handling for SPI GPIOs if used */
-       if (IS_ERR(desc))
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
+               /* Special handling for SPI GPIOs if used */
                desc = of_find_spi_gpio(dev, con_id, &of_flags);
-       if (IS_ERR(desc)) {
+       }
+
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
                /* This quirk looks up flags and all */
                desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
                if (!IS_ERR(desc))
                        return desc;
        }
 
-       /* Special handling for regulator GPIOs if used */
-       if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) {
+               /* Special handling for regulator GPIOs if used */
                desc = of_find_regulator_gpio(dev, con_id, &of_flags);
+       }
+
+       if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
+               desc = of_find_arizona_gpio(dev, con_id, &of_flags);
 
        if (IS_ERR(desc))
                return desc;
@@ -523,8 +644,9 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
  * GPIO chips. This function performs only one sanity check: whether GPIO
  * is less than ngpios (that is specified in the gpio_chip).
  */
-int of_gpio_simple_xlate(struct gpio_chip *gc,
-                        const struct of_phandle_args *gpiospec, u32 *flags)
+static int of_gpio_simple_xlate(struct gpio_chip *gc,
+                               const struct of_phandle_args *gpiospec,
+                               u32 *flags)
 {
        /*
         * We're discouraging gpio_cells < 2, since that way you'll have to
@@ -548,7 +670,6 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
 
        return gpiospec->args[0];
 }
-EXPORT_SYMBOL(of_gpio_simple_xlate);
 
 /**
  * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
@@ -605,7 +726,7 @@ err0:
        pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
        return ret;
 }
-EXPORT_SYMBOL(of_mm_gpiochip_add_data);
+EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data);
 
 /**
  * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
@@ -622,7 +743,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
        iounmap(mm_gc->regs);
        kfree(gc->label);
 }
-EXPORT_SYMBOL(of_mm_gpiochip_remove);
+EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
 
 static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
 {
@@ -734,7 +855,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
 
 int of_gpiochip_add(struct gpio_chip *chip)
 {
-       int status;
+       int ret;
 
        if (!chip->of_node)
                return 0;
@@ -749,9 +870,9 @@ int of_gpiochip_add(struct gpio_chip *chip)
 
        of_gpiochip_init_valid_mask(chip);
 
-       status = of_gpiochip_add_pin_range(chip);
-       if (status)
-               return status;
+       ret = of_gpiochip_add_pin_range(chip);
+       if (ret)
+               return ret;
 
        /* If the chip defines names itself, these take precedence */
        if (!chip->names)
@@ -760,13 +881,13 @@ int of_gpiochip_add(struct gpio_chip *chip)
 
        of_node_get(chip->of_node);
 
-       status = of_gpiochip_scan_gpios(chip);
-       if (status) {
+       ret = of_gpiochip_scan_gpios(chip);
+       if (ret) {
                of_node_put(chip->of_node);
                gpiochip_remove_pin_ranges(chip);
        }
 
-       return status;
+       return ret;
 }
 
 void of_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
new file mode 100644 (file)
index 0000000..9768831
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef GPIOLIB_OF_H
+#define GPIOLIB_OF_H
+
+struct gpio_chip;
+enum of_gpio_flags;
+
+#ifdef CONFIG_OF_GPIO
+struct gpio_desc *of_find_gpio(struct device *dev,
+                              const char *con_id,
+                              unsigned int idx,
+                              unsigned long *lookupflags);
+int of_gpiochip_add(struct gpio_chip *gc);
+void of_gpiochip_remove(struct gpio_chip *gc);
+int of_gpio_get_count(struct device *dev, const char *con_id);
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
+#else
+static inline struct gpio_desc *of_find_gpio(struct device *dev,
+                                            const char *con_id,
+                                            unsigned int idx,
+                                            unsigned long *lookupflags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
+static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
+static inline int of_gpio_get_count(struct device *dev, const char *con_id)
+{
+       return 0;
+}
+static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
+{
+       return false;
+}
+#endif /* CONFIG_OF_GPIO */
+
+#endif /* GPIOLIB_OF_H */
index f497003..8229888 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
-#include <linux/of_gpio.h>
 #include <linux/idr.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -30,6 +29,8 @@
 #include <uapi/linux/gpio.h>
 
 #include "gpiolib.h"
+#include "gpiolib-of.h"
+#include "gpiolib-acpi.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/gpio.h>
@@ -213,7 +214,7 @@ int gpiod_get_direction(struct gpio_desc *desc)
 {
        struct gpio_chip *chip;
        unsigned offset;
-       int status;
+       int ret;
 
        chip = gpiod_to_chip(desc);
        offset = gpio_chip_hwgpio(desc);
@@ -221,17 +222,17 @@ int gpiod_get_direction(struct gpio_desc *desc)
        if (!chip->get_direction)
                return -ENOTSUPP;
 
-       status = chip->get_direction(chip, offset);
-       if (status > 0) {
+       ret = chip->get_direction(chip, offset);
+       if (ret > 0) {
                /* GPIOF_DIR_IN, or other positive */
-               status = 1;
+               ret = 1;
                clear_bit(FLAG_IS_OUT, &desc->flags);
        }
-       if (status == 0) {
+       if (ret == 0) {
                /* GPIOF_DIR_OUT */
                set_bit(FLAG_IS_OUT, &desc->flags);
        }
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiod_get_direction);
 
@@ -350,7 +351,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
 {
        unsigned long *p;
 
-       p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL);
+       p = bitmap_alloc(chip->ngpio, GFP_KERNEL);
        if (!p)
                return NULL;
 
@@ -360,38 +361,31 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
        return p;
 }
 
-static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
 {
-#ifdef CONFIG_OF_GPIO
-       int size;
-       struct device_node *np = gpiochip->of_node;
-
-       size = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
-       if (size > 0 && size % 2 == 0)
-               gpiochip->need_valid_mask = true;
-#endif
-
-       if (!gpiochip->need_valid_mask)
+       if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask))
                return 0;
 
-       gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip);
-       if (!gpiochip->valid_mask)
+       gc->valid_mask = gpiochip_allocate_mask(gc);
+       if (!gc->valid_mask)
                return -ENOMEM;
 
        return 0;
 }
 
-static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_init_valid_mask(struct gpio_chip *gc)
 {
-       if (gpiochip->init_valid_mask)
-               return gpiochip->init_valid_mask(gpiochip);
+       if (gc->init_valid_mask)
+               return gc->init_valid_mask(gc,
+                                          gc->valid_mask,
+                                          gc->ngpio);
 
        return 0;
 }
 
 static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-       kfree(gpiochip->valid_mask);
+       bitmap_free(gpiochip->valid_mask);
        gpiochip->valid_mask = NULL;
 }
 
@@ -535,6 +529,14 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
        if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
                return -EINVAL;
 
+       /*
+        * Do not allow both INPUT & OUTPUT flags to be set as they are
+        * contradictory.
+        */
+       if ((lflags & GPIOHANDLE_REQUEST_INPUT) &&
+           (lflags & GPIOHANDLE_REQUEST_OUTPUT))
+               return -EINVAL;
+
        /*
         * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
         * the hardware actually supports enabling both at the same time the
@@ -857,7 +859,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
        }
 
        ret = kfifo_put(&le->events, ge);
-       if (ret != 0)
+       if (ret)
                wake_up_poll(&le->wait, EPOLLIN);
 
        return IRQ_HANDLED;
@@ -926,7 +928,9 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        }
 
        /* This is just wrong: we don't look for events on output lines */
-       if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) {
                ret = -EINVAL;
                goto out_free_label;
        }
@@ -940,10 +944,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
 
        if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
                set_bit(FLAG_ACTIVE_LOW, &desc->flags);
-       if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
-               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-       if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
-               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 
        ret = gpiod_direction_input(desc);
        if (ret)
@@ -1091,9 +1091,11 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                        lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
                if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_OPEN_DRAIN;
+                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
+                                          GPIOLINE_FLAG_IS_OUT);
                if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_OPEN_SOURCE;
+                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
+                                          GPIOLINE_FLAG_IS_OUT);
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
@@ -1174,21 +1176,21 @@ static void gpiodevice_release(struct device *dev)
 
 static int gpiochip_setup_dev(struct gpio_device *gdev)
 {
-       int status;
+       int ret;
 
        cdev_init(&gdev->chrdev, &gpio_fileops);
        gdev->chrdev.owner = THIS_MODULE;
        gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
 
-       status = cdev_device_add(&gdev->chrdev, &gdev->dev);
-       if (status)
-               return status;
+       ret = cdev_device_add(&gdev->chrdev, &gdev->dev);
+       if (ret)
+               return ret;
 
        chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
                 MAJOR(gpio_devt), gdev->id);
 
-       status = gpiochip_sysfs_register(gdev);
-       if (status)
+       ret = gpiochip_sysfs_register(gdev);
+       if (ret)
                goto err_remove_device;
 
        /* From this point, the .release() function cleans up gpio_device */
@@ -1201,7 +1203,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
 
 err_remove_device:
        cdev_device_del(&gdev->chrdev, &gdev->dev);
-       return status;
+       return ret;
 }
 
 static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog)
@@ -1242,13 +1244,13 @@ static void machine_gpiochip_add(struct gpio_chip *chip)
 static void gpiochip_setup_devs(void)
 {
        struct gpio_device *gdev;
-       int err;
+       int ret;
 
        list_for_each_entry(gdev, &gpio_devices, list) {
-               err = gpiochip_setup_dev(gdev);
-               if (err)
+               ret = gpiochip_setup_dev(gdev);
+               if (ret)
                        pr_err("%s: Failed to initialize gpio device (%d)\n",
-                              dev_name(&gdev->dev), err);
+                              dev_name(&gdev->dev), ret);
        }
 }
 
@@ -1257,7 +1259,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
                               struct lock_class_key *request_key)
 {
        unsigned long   flags;
-       int             status = 0;
+       int             ret = 0;
        unsigned        i;
        int             base = chip->base;
        struct gpio_device *gdev;
@@ -1287,7 +1289,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
        if (gdev->id < 0) {
-               status = gdev->id;
+               ret = gdev->id;
                goto err_free_gdev;
        }
        dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);
@@ -1303,13 +1305,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
        if (!gdev->descs) {
-               status = -ENOMEM;
+               ret = -ENOMEM;
                goto err_free_ida;
        }
 
        if (chip->ngpio == 0) {
                chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
-               status = -EINVAL;
+               ret = -EINVAL;
                goto err_free_descs;
        }
 
@@ -1319,7 +1321,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL);
        if (!gdev->label) {
-               status = -ENOMEM;
+               ret = -ENOMEM;
                goto err_free_descs;
        }
 
@@ -1338,7 +1340,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (base < 0) {
                base = gpiochip_find_base(chip->ngpio);
                if (base < 0) {
-                       status = base;
+                       ret = base;
                        spin_unlock_irqrestore(&gpio_lock, flags);
                        goto err_free_label;
                }
@@ -1352,8 +1354,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        }
        gdev->base = base;
 
-       status = gpiodev_add_to_list(gdev);
-       if (status) {
+       ret = gpiodev_add_to_list(gdev);
+       if (ret) {
                spin_unlock_irqrestore(&gpio_lock, flags);
                goto err_free_label;
        }
@@ -1367,28 +1369,20 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        INIT_LIST_HEAD(&gdev->pin_ranges);
 #endif
 
-       status = gpiochip_set_desc_names(chip);
-       if (status)
+       ret = gpiochip_set_desc_names(chip);
+       if (ret)
                goto err_remove_from_list;
 
-       status = gpiochip_irqchip_init_valid_mask(chip);
-       if (status)
+       ret = gpiochip_alloc_valid_mask(chip);
+       if (ret)
                goto err_remove_from_list;
 
-       status = gpiochip_alloc_valid_mask(chip);
-       if (status)
-               goto err_remove_irqchip_mask;
-
-       status = gpiochip_add_irqchip(chip, lock_key, request_key);
-       if (status)
+       ret = of_gpiochip_add(chip);
+       if (ret)
                goto err_free_gpiochip_mask;
 
-       status = of_gpiochip_add(chip);
-       if (status)
-               goto err_remove_chip;
-
-       status = gpiochip_init_valid_mask(chip);
-       if (status)
+       ret = gpiochip_init_valid_mask(chip);
+       if (ret)
                goto err_remove_of_chip;
 
        for (i = 0; i < chip->ngpio; i++) {
@@ -1411,6 +1405,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        machine_gpiochip_add(chip);
 
+       ret = gpiochip_irqchip_init_valid_mask(chip);
+       if (ret)
+               goto err_remove_acpi_chip;
+
+       ret = gpiochip_add_irqchip(chip, lock_key, request_key);
+       if (ret)
+               goto err_remove_irqchip_mask;
+
        /*
         * By first adding the chardev, and then adding the device,
         * we get a device node entry in sysfs under
@@ -1420,23 +1422,23 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
         * Otherwise, defer until later.
         */
        if (gpiolib_initialized) {
-               status = gpiochip_setup_dev(gdev);
-               if (status)
-                       goto err_remove_acpi_chip;
+               ret = gpiochip_setup_dev(gdev);
+               if (ret)
+                       goto err_remove_irqchip;
        }
        return 0;
 
+err_remove_irqchip:
+       gpiochip_irqchip_remove(chip);
+err_remove_irqchip_mask:
+       gpiochip_irqchip_free_valid_mask(chip);
 err_remove_acpi_chip:
        acpi_gpiochip_remove(chip);
 err_remove_of_chip:
        gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
-err_remove_chip:
-       gpiochip_irqchip_remove(chip);
 err_free_gpiochip_mask:
        gpiochip_free_valid_mask(chip);
-err_remove_irqchip_mask:
-       gpiochip_irqchip_free_valid_mask(chip);
 err_remove_from_list:
        spin_lock_irqsave(&gpio_lock, flags);
        list_del(&gdev->list);
@@ -1451,9 +1453,9 @@ err_free_gdev:
        /* failures here can mean systems won't boot... */
        pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
               gdev->base, gdev->base + gdev->ngpio - 1,
-              chip->label ? : "generic", status);
+              chip->label ? : "generic", ret);
        kfree(gdev);
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
 
@@ -1619,21 +1621,25 @@ static struct gpio_chip *find_chip_by_name(const char *name)
  * The following is irqchip helper code for gpiochips.
  */
 
-static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc)
 {
-       if (!gpiochip->irq.need_valid_mask)
+       struct gpio_irq_chip *girq = &gc->irq;
+
+       if (!girq->init_valid_mask)
                return 0;
 
-       gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip);
-       if (!gpiochip->irq.valid_mask)
+       girq->valid_mask = gpiochip_allocate_mask(gc);
+       if (!girq->valid_mask)
                return -ENOMEM;
 
+       girq->init_valid_mask(gc, girq->valid_mask, gc->ngpio);
+
        return 0;
 }
 
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-       kfree(gpiochip->irq.valid_mask);
+       bitmap_free(gpiochip->irq.valid_mask);
        gpiochip->irq.valid_mask = NULL;
 }
 
@@ -1733,6 +1739,273 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
 
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+
+/**
+ * gpiochip_set_hierarchical_irqchip() - connects a hierarchical irqchip
+ * to a gpiochip
+ * @gc: the gpiochip to set the irqchip hierarchical handler to
+ * @irqchip: the irqchip to handle this level of the hierarchy, the interrupt
+ * will then percolate up to the parent
+ */
+static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
+                                             struct irq_chip *irqchip)
+{
+       /* DT will deal with mapping each IRQ as we go along */
+       if (is_of_node(gc->irq.fwnode))
+               return;
+
+       /*
+        * This is for legacy and boardfile "irqchip" fwnodes: allocate
+        * irqs upfront instead of dynamically since we don't have the
+        * dynamic type of allocation that hardware description languages
+        * provide. Once all GPIO drivers using board files are gone from
+        * the kernel we can delete this code, but for a transitional period
+        * it is necessary to keep this around.
+        */
+       if (is_fwnode_irqchip(gc->irq.fwnode)) {
+               int i;
+               int ret;
+
+               for (i = 0; i < gc->ngpio; i++) {
+                       struct irq_fwspec fwspec;
+                       unsigned int parent_hwirq;
+                       unsigned int parent_type;
+                       struct gpio_irq_chip *girq = &gc->irq;
+
+                       /*
+                        * We call the child to parent translation function
+                        * only to check if the child IRQ is valid or not.
+                        * Just pick the rising edge type here as that is what
+                        * we likely need to support.
+                        */
+                       ret = girq->child_to_parent_hwirq(gc, i,
+                                                         IRQ_TYPE_EDGE_RISING,
+                                                         &parent_hwirq,
+                                                         &parent_type);
+                       if (ret) {
+                               chip_err(gc, "skip set-up on hwirq %d\n",
+                                        i);
+                               continue;
+                       }
+
+                       fwspec.fwnode = gc->irq.fwnode;
+                       /* This is the hwirq for the GPIO line side of things */
+                       fwspec.param[0] = girq->child_offset_to_irq(gc, i);
+                       /* Just pick something */
+                       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+                       fwspec.param_count = 2;
+                       ret = __irq_domain_alloc_irqs(gc->irq.domain,
+                                                     /* just pick something */
+                                                     -1,
+                                                     1,
+                                                     NUMA_NO_NODE,
+                                                     &fwspec,
+                                                     false,
+                                                     NULL);
+                       if (ret < 0) {
+                               chip_err(gc,
+                                        "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
+                                        i, parent_hwirq,
+                                        ret);
+                       }
+               }
+       }
+
+       chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__);
+
+       return;
+}
+
+static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d,
+                                                  struct irq_fwspec *fwspec,
+                                                  unsigned long *hwirq,
+                                                  unsigned int *type)
+{
+       /* We support standard DT translation */
+       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
+               return irq_domain_translate_twocell(d, fwspec, hwirq, type);
+       }
+
+       /* This is for board files and others not using DT */
+       if (is_fwnode_irqchip(fwspec->fwnode)) {
+               int ret;
+
+               ret = irq_domain_translate_twocell(d, fwspec, hwirq, type);
+               if (ret)
+                       return ret;
+               WARN_ON(*type == IRQ_TYPE_NONE);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
+                                              unsigned int irq,
+                                              unsigned int nr_irqs,
+                                              void *data)
+{
+       struct gpio_chip *gc = d->host_data;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       struct irq_fwspec *fwspec = data;
+       struct irq_fwspec parent_fwspec;
+       unsigned int parent_hwirq;
+       unsigned int parent_type;
+       struct gpio_irq_chip *girq = &gc->irq;
+       int ret;
+
+       /*
+        * The nr_irqs parameter is always one except for PCI multi-MSI
+        * so this should not happen.
+        */
+       WARN_ON(nr_irqs != 1);
+
+       ret = gc->irq.child_irq_domain_ops.translate(d, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       chip_info(gc, "allocate IRQ %d, hwirq %lu\n", irq,  hwirq);
+
+       ret = girq->child_to_parent_hwirq(gc, hwirq, type,
+                                         &parent_hwirq, &parent_type);
+       if (ret) {
+               chip_err(gc, "can't look up hwirq %lu\n", hwirq);
+               return ret;
+       }
+       chip_info(gc, "found parent hwirq %u\n", parent_hwirq);
+
+       /*
+        * We set handle_bad_irq because the .set_type() should
+        * always be invoked and set the right type of handler.
+        */
+       irq_domain_set_info(d,
+                           irq,
+                           hwirq,
+                           gc->irq.chip,
+                           gc,
+                           girq->handler,
+                           NULL, NULL);
+       irq_set_probe(irq);
+
+       /*
+        * Create a IRQ fwspec to send up to the parent irqdomain:
+        * specify the hwirq we address on the parent and tie it
+        * all together up the chain.
+        */
+       parent_fwspec.fwnode = d->parent->fwnode;
+       /* This parent only handles asserted level IRQs */
+       girq->populate_parent_fwspec(gc, &parent_fwspec, parent_hwirq,
+                                    parent_type);
+       chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
+                 irq, parent_hwirq);
+       ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec);
+       if (ret)
+               chip_err(gc,
+                        "failed to allocate parent hwirq %d for hwirq %lu\n",
+                        parent_hwirq, hwirq);
+
+       return ret;
+}
+
+static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *chip,
+                                                     unsigned int offset)
+{
+       return offset;
+}
+
+static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops)
+{
+       ops->activate = gpiochip_irq_domain_activate;
+       ops->deactivate = gpiochip_irq_domain_deactivate;
+       ops->alloc = gpiochip_hierarchy_irq_domain_alloc;
+       ops->free = irq_domain_free_irqs_common;
+
+       /*
+        * We only allow overriding the translate() function for
+        * hierarchical chips, and this should only be done if the user
+        * really need something other than 1:1 translation.
+        */
+       if (!ops->translate)
+               ops->translate = gpiochip_hierarchy_irq_domain_translate;
+}
+
+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+{
+       if (!gc->irq.child_to_parent_hwirq ||
+           !gc->irq.fwnode) {
+               chip_err(gc, "missing irqdomain vital data\n");
+               return -EINVAL;
+       }
+
+       if (!gc->irq.child_offset_to_irq)
+               gc->irq.child_offset_to_irq = gpiochip_child_offset_to_irq_noop;
+
+       if (!gc->irq.populate_parent_fwspec)
+               gc->irq.populate_parent_fwspec =
+                       gpiochip_populate_parent_fwspec_twocell;
+
+       gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops);
+
+       gc->irq.domain = irq_domain_create_hierarchy(
+               gc->irq.parent_domain,
+               0,
+               gc->ngpio,
+               gc->irq.fwnode,
+               &gc->irq.child_irq_domain_ops,
+               gc);
+
+       if (!gc->irq.domain)
+               return -ENOMEM;
+
+       gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip);
+
+       return 0;
+}
+
+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
+{
+       return !!gc->irq.parent_domain;
+}
+
+void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                            struct irq_fwspec *fwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
+{
+       fwspec->param_count = 2;
+       fwspec->param[0] = parent_hwirq;
+       fwspec->param[1] = parent_type;
+}
+EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
+
+void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                             struct irq_fwspec *fwspec,
+                                             unsigned int parent_hwirq,
+                                             unsigned int parent_type)
+{
+       fwspec->param_count = 4;
+       fwspec->param[0] = 0;
+       fwspec->param[1] = parent_hwirq;
+       fwspec->param[2] = 0;
+       fwspec->param[3] = parent_type;
+}
+EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
+
+#else
+
+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+{
+       return -EINVAL;
+}
+
+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
+{
+       return false;
+}
+
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
+
 /**
  * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
  * @d: the irqdomain used by this irqchip
@@ -1747,7 +2020,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq)
 {
        struct gpio_chip *chip = d->host_data;
-       int err = 0;
+       int ret = 0;
 
        if (!gpiochip_irqchip_irq_valid(chip, hwirq))
                return -ENXIO;
@@ -1765,12 +2038,12 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
        irq_set_noprobe(irq);
 
        if (chip->irq.num_parents == 1)
-               err = irq_set_parent(irq, chip->irq.parents[0]);
+               ret = irq_set_parent(irq, chip->irq.parents[0]);
        else if (chip->irq.map)
-               err = irq_set_parent(irq, chip->irq.map[hwirq]);
+               ret = irq_set_parent(irq, chip->irq.map[hwirq]);
 
-       if (err < 0)
-               return err;
+       if (ret < 0)
+               return ret;
 
        /*
         * No set-up of the hardware will happen if IRQ_TYPE_NONE
@@ -1801,6 +2074,11 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
+/*
+ * TODO: move these activate/deactivate in under the hierarchicial
+ * irqchip implementation as static once SPMI and SSBI (all external
+ * users) are phased over.
+ */
 /**
  * gpiochip_irq_domain_activate() - Lock a GPIO to be used as an IRQ
  * @domain: The IRQ domain used by this IRQ chip
@@ -1840,10 +2118,25 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+       struct irq_domain *domain = chip->irq.domain;
+
        if (!gpiochip_irqchip_irq_valid(chip, offset))
                return -ENXIO;
 
-       return irq_create_mapping(chip->irq.domain, offset);
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       if (irq_domain_is_hierarchy(domain)) {
+               struct irq_fwspec spec;
+
+               spec.fwnode = domain->fwnode;
+               spec.param_count = 2;
+               spec.param[0] = chip->irq.child_offset_to_irq(chip, offset);
+               spec.param[1] = IRQ_TYPE_NONE;
+
+               return irq_create_fwspec_mapping(&spec);
+       }
+#endif
+
+       return irq_create_mapping(domain, offset);
 }
 
 static int gpiochip_irq_reqres(struct irq_data *d)
@@ -1920,7 +2213,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
                                struct lock_class_key *request_key)
 {
        struct irq_chip *irqchip = gpiochip->irq.chip;
-       const struct irq_domain_ops *ops;
+       const struct irq_domain_ops *ops = NULL;
        struct device_node *np;
        unsigned int type;
        unsigned int i;
@@ -1956,16 +2249,25 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
        gpiochip->irq.lock_key = lock_key;
        gpiochip->irq.request_key = request_key;
 
-       if (gpiochip->irq.domain_ops)
-               ops = gpiochip->irq.domain_ops;
-       else
-               ops = &gpiochip_domain_ops;
-
-       gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-                                                    gpiochip->irq.first,
-                                                    ops, gpiochip);
-       if (!gpiochip->irq.domain)
-               return -EINVAL;
+       /* If a parent irqdomain is provided, let's build a hierarchy */
+       if (gpiochip_hierarchy_is_hierarchical(gpiochip)) {
+               int ret = gpiochip_hierarchy_add_domain(gpiochip);
+               if (ret)
+                       return ret;
+       } else {
+               /* Some drivers provide custom irqdomain ops */
+               if (gpiochip->irq.domain_ops)
+                       ops = gpiochip->irq.domain_ops;
+
+               if (!ops)
+                       ops = &gpiochip_domain_ops;
+               gpiochip->irq.domain = irq_domain_add_simple(np,
+                       gpiochip->ngpio,
+                       gpiochip->irq.first,
+                       ops, gpiochip);
+               if (!gpiochip->irq.domain)
+                       return -EINVAL;
+       }
 
        if (gpiochip->irq.parent_handler) {
                void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
@@ -2328,7 +2630,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
 static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 {
        struct gpio_chip        *chip = desc->gdev->chip;
-       int                     status;
+       int                     ret;
        unsigned long           flags;
        unsigned                offset;
 
@@ -2346,10 +2648,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 
        if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
                desc_set_label(desc, label ? : "?");
-               status = 0;
+               ret = 0;
        } else {
                kfree_const(label);
-               status = -EBUSY;
+               ret = -EBUSY;
                goto done;
        }
 
@@ -2358,12 +2660,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
                spin_unlock_irqrestore(&gpio_lock, flags);
                offset = gpio_chip_hwgpio(desc);
                if (gpiochip_line_is_valid(chip, offset))
-                       status = chip->request(chip, offset);
+                       ret = chip->request(chip, offset);
                else
-                       status = -EINVAL;
+                       ret = -EINVAL;
                spin_lock_irqsave(&gpio_lock, flags);
 
-               if (status < 0) {
+               if (ret < 0) {
                        desc_set_label(desc, NULL);
                        kfree_const(label);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
@@ -2378,7 +2680,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
        }
 done:
        spin_unlock_irqrestore(&gpio_lock, flags);
-       return status;
+       return ret;
 }
 
 /*
@@ -2421,24 +2723,24 @@ static int validate_desc(const struct gpio_desc *desc, const char *func)
 
 int gpiod_request(struct gpio_desc *desc, const char *label)
 {
-       int status = -EPROBE_DEFER;
+       int ret = -EPROBE_DEFER;
        struct gpio_device *gdev;
 
        VALIDATE_DESC(desc);
        gdev = desc->gdev;
 
        if (try_module_get(gdev->owner)) {
-               status = gpiod_request_commit(desc, label);
-               if (status < 0)
+               ret = gpiod_request_commit(desc, label);
+               if (ret < 0)
                        module_put(gdev->owner);
                else
                        get_device(&gdev->dev);
        }
 
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       if (ret)
+               gpiod_dbg(desc, "%s: status %d\n", __func__, ret);
 
-       return status;
+       return ret;
 }
 
 static bool gpiod_free_commit(struct gpio_desc *desc)
@@ -2540,22 +2842,22 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
                                            enum gpiod_flags dflags)
 {
        struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
-       int err;
+       int ret;
 
        if (IS_ERR(desc)) {
                chip_err(chip, "failed to get GPIO descriptor\n");
                return desc;
        }
 
-       err = gpiod_request_commit(desc, label);
-       if (err < 0)
-               return ERR_PTR(err);
+       ret = gpiod_request_commit(desc, label);
+       if (ret < 0)
+               return ERR_PTR(ret);
 
-       err = gpiod_configure_flags(desc, label, lflags, dflags);
-       if (err) {
+       ret = gpiod_configure_flags(desc, label, lflags, dflags);
+       if (ret) {
                chip_err(chip, "setup of own GPIO %s failed\n", label);
                gpiod_free_commit(desc);
-               return ERR_PTR(err);
+               return ERR_PTR(ret);
        }
 
        return desc;
@@ -2618,7 +2920,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
 int gpiod_direction_input(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
-       int                     status = 0;
+       int                     ret = 0;
 
        VALIDATE_DESC(desc);
        chip = desc->gdev->chip;
@@ -2642,7 +2944,7 @@ int gpiod_direction_input(struct gpio_desc *desc)
         * assume we are in input mode after this.
         */
        if (chip->direction_input) {
-               status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+               ret = chip->direction_input(chip, gpio_chip_hwgpio(desc));
        } else if (chip->get_direction &&
                  (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
                gpiod_warn(desc,
@@ -2650,7 +2952,7 @@ int gpiod_direction_input(struct gpio_desc *desc)
                           __func__);
                return -EIO;
        }
-       if (status == 0)
+       if (ret == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
        if (test_bit(FLAG_PULL_UP, &desc->flags))
@@ -2660,9 +2962,9 @@ int gpiod_direction_input(struct gpio_desc *desc)
                gpio_set_config(chip, gpio_chip_hwgpio(desc),
                                PIN_CONFIG_BIAS_PULL_DOWN);
 
-       trace_gpio_direction(desc_to_gpio(desc), 1, status);
+       trace_gpio_direction(desc_to_gpio(desc), 1, ret);
 
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
@@ -2934,7 +3236,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                                  struct gpio_array *array_info,
                                  unsigned long *value_bitmap)
 {
-       int err, i = 0;
+       int ret, i = 0;
 
        /*
         * Validate array_info against desc_array and its size.
@@ -2947,11 +3249,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                if (!can_sleep)
                        WARN_ON(array_info->chip->can_sleep);
 
-               err = gpio_chip_get_multiple(array_info->chip,
+               ret = gpio_chip_get_multiple(array_info->chip,
                                             array_info->get_mask,
                                             value_bitmap);
-               if (err)
-                       return err;
+               if (ret)
+                       return ret;
 
                if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
                        bitmap_xor(value_bitmap, value_bitmap,
@@ -3139,24 +3441,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value);
  */
 static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
 {
-       int err = 0;
+       int ret = 0;
        struct gpio_chip *chip = desc->gdev->chip;
        int offset = gpio_chip_hwgpio(desc);
 
        if (value) {
-               err = chip->direction_input(chip, offset);
-               if (!err)
+               ret = chip->direction_input(chip, offset);
+               if (!ret)
                        clear_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_output(chip, offset, 0);
-               if (!err)
+               ret = chip->direction_output(chip, offset, 0);
+               if (!ret)
                        set_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(desc_to_gpio(desc), value, err);
-       if (err < 0)
+       trace_gpio_direction(desc_to_gpio(desc), value, ret);
+       if (ret < 0)
                gpiod_err(desc,
                          "%s: Error in set_value for open drain err %d\n",
-                         __func__, err);
+                         __func__, ret);
 }
 
 /*
@@ -3166,24 +3468,24 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
  */
 static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
 {
-       int err = 0;
+       int ret = 0;
        struct gpio_chip *chip = desc->gdev->chip;
        int offset = gpio_chip_hwgpio(desc);
 
        if (value) {
-               err = chip->direction_output(chip, offset, 1);
-               if (!err)
+               ret = chip->direction_output(chip, offset, 1);
+               if (!ret)
                        set_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_input(chip, offset);
-               if (!err)
+               ret = chip->direction_input(chip, offset);
+               if (!ret)
                        clear_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(desc_to_gpio(desc), !value, err);
-       if (err < 0)
+       trace_gpio_direction(desc_to_gpio(desc), !value, ret);
+       if (ret < 0)
                gpiod_err(desc,
                          "%s: Error in set_value for open source err %d\n",
-                         __func__, err);
+                         __func__, ret);
 }
 
 static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
@@ -4000,27 +4302,6 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
        return desc;
 }
 
-static int dt_gpio_count(struct device *dev, const char *con_id)
-{
-       int ret;
-       char propname[32];
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(propname, sizeof(propname), "%s-%s",
-                                con_id, gpio_suffixes[i]);
-               else
-                       snprintf(propname, sizeof(propname), "%s",
-                                gpio_suffixes[i]);
-
-               ret = of_gpio_named_count(dev->of_node, propname);
-               if (ret > 0)
-                       break;
-       }
-       return ret ? ret : -ENOENT;
-}
-
 static int platform_gpio_count(struct device *dev, const char *con_id)
 {
        struct gpiod_lookup_table *table;
@@ -4053,7 +4334,7 @@ int gpiod_count(struct device *dev, const char *con_id)
        int count = -ENOENT;
 
        if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
-               count = dt_gpio_count(dev, con_id);
+               count = of_gpio_get_count(dev, con_id);
        else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
                count = acpi_gpio_count(dev, con_id);
 
@@ -4115,7 +4396,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
 int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags)
 {
-       int status;
+       int ret;
 
        if (lflags & GPIO_ACTIVE_LOW)
                set_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -4148,9 +4429,9 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
        else if (lflags & GPIO_PULL_DOWN)
                set_bit(FLAG_PULL_DOWN, &desc->flags);
 
-       status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
-       if (status < 0)
-               return status;
+       ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
+       if (ret < 0)
+               return ret;
 
        /* No particular flag request, return here... */
        if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
@@ -4160,12 +4441,12 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
 
        /* Process flags */
        if (dflags & GPIOD_FLAGS_BIT_DIR_OUT)
-               status = gpiod_direction_output(desc,
+               ret = gpiod_direction_output(desc,
                                !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL));
        else
-               status = gpiod_direction_input(desc);
+               ret = gpiod_direction_input(desc);
 
-       return status;
+       return ret;
 }
 
 /**
@@ -4189,7 +4470,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 {
        unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc = NULL;
-       int status;
+       int ret;
        /* Maybe we have a device name, maybe not */
        const char *devname = dev ? dev_name(dev) : "?";
 
@@ -4224,9 +4505,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
         * If a connection label was passed use that, else attempt to use
         * the device name as label
         */
-       status = gpiod_request(desc, con_id ? con_id : devname);
-       if (status < 0) {
-               if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+       ret = gpiod_request(desc, con_id ? con_id : devname);
+       if (ret < 0) {
+               if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
                        /*
                         * This happens when there are several consumers for
                         * the same GPIO line: we just return here without
@@ -4239,89 +4520,20 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
                                 con_id ? con_id : devname);
                        return desc;
                } else {
-                       return ERR_PTR(status);
+                       return ERR_PTR(ret);
                }
        }
 
-       status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
-       if (status < 0) {
-               dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
-               gpiod_put(desc);
-               return ERR_PTR(status);
-       }
-
-       return desc;
-}
-EXPORT_SYMBOL_GPL(gpiod_get_index);
-
-/**
- * gpiod_get_from_of_node() - obtain a GPIO from an OF node
- * @node:      handle of the OF node
- * @propname:  name of the DT property representing the GPIO
- * @index:     index of the GPIO to obtain for the consumer
- * @dflags:    GPIO initialization flags
- * @label:     label to attach to the requested GPIO
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label)
-{
-       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       struct gpio_desc *desc;
-       enum of_gpio_flags flags;
-       bool active_low = false;
-       bool single_ended = false;
-       bool open_drain = false;
-       bool transitory = false;
-       int ret;
-
-       desc = of_get_named_gpiod_flags(node, propname,
-                                       index, &flags);
-
-       if (!desc || IS_ERR(desc)) {
-               return desc;
-       }
-
-       active_low = flags & OF_GPIO_ACTIVE_LOW;
-       single_ended = flags & OF_GPIO_SINGLE_ENDED;
-       open_drain = flags & OF_GPIO_OPEN_DRAIN;
-       transitory = flags & OF_GPIO_TRANSITORY;
-
-       ret = gpiod_request(desc, label);
-       if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
-               return desc;
-       if (ret)
-               return ERR_PTR(ret);
-
-       if (active_low)
-               lflags |= GPIO_ACTIVE_LOW;
-
-       if (single_ended) {
-               if (open_drain)
-                       lflags |= GPIO_OPEN_DRAIN;
-               else
-                       lflags |= GPIO_OPEN_SOURCE;
-       }
-
-       if (transitory)
-               lflags |= GPIO_TRANSITORY;
-
-       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
        if (ret < 0) {
+               dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
                gpiod_put(desc);
                return ERR_PTR(ret);
        }
 
        return desc;
 }
-EXPORT_SYMBOL(gpiod_get_from_of_node);
+EXPORT_SYMBOL_GPL(gpiod_get_index);
 
 /**
  * fwnode_get_named_gpiod - obtain a GPIO from firmware node
@@ -4431,7 +4643,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
        struct gpio_chip *chip;
        struct gpio_desc *local_desc;
        int hwnum;
-       int status;
+       int ret;
 
        chip = gpiod_to_chip(desc);
        hwnum = gpio_chip_hwgpio(desc);
@@ -4439,10 +4651,10 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
        local_desc = gpiochip_request_own_desc(chip, hwnum, name,
                                               lflags, dflags);
        if (IS_ERR(local_desc)) {
-               status = PTR_ERR(local_desc);
+               ret = PTR_ERR(local_desc);
                pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
-                      name, chip->label, hwnum, status);
-               return status;
+                      name, chip->label, hwnum, ret);
+               return ret;
        }
 
        /* Mark GPIO as hogged so it can be identified and removed later */
index 7c52c24..b8b10a4 100644 (file)
@@ -16,9 +16,6 @@
 #include <linux/module.h>
 #include <linux/cdev.h>
 
-enum of_gpio_flags;
-struct acpi_device;
-
 /**
  * struct gpio_device - internal state container for GPIO devices
  * @id: numerical ID number for the GPIO chip
@@ -69,126 +66,9 @@ struct gpio_device {
 #endif
 };
 
-/**
- * struct acpi_gpio_info - ACPI GPIO specific information
- * @adev: reference to ACPI device which consumes GPIO resource
- * @flags: GPIO initialization flags
- * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
- * @pin_config: pin bias as provided by ACPI
- * @polarity: interrupt polarity as provided by ACPI
- * @triggering: triggering type as provided by ACPI
- * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
- */
-struct acpi_gpio_info {
-       struct acpi_device *adev;
-       enum gpiod_flags flags;
-       bool gpioint;
-       int pin_config;
-       int polarity;
-       int triggering;
-       unsigned int quirks;
-};
-
 /* gpio suffixes used for ACPI and device tree lookup */
 static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
 
-#ifdef CONFIG_OF_GPIO
-struct gpio_desc *of_find_gpio(struct device *dev,
-                              const char *con_id,
-                              unsigned int idx,
-                              unsigned long *lookupflags);
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
-                  const char *list_name, int index, enum of_gpio_flags *flags);
-int of_gpiochip_add(struct gpio_chip *gc);
-void of_gpiochip_remove(struct gpio_chip *gc);
-#else
-static inline struct gpio_desc *of_find_gpio(struct device *dev,
-                                            const char *con_id,
-                                            unsigned int idx,
-                                            unsigned long *lookupflags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
-                  const char *list_name, int index, enum of_gpio_flags *flags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
-static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
-#endif /* CONFIG_OF_GPIO */
-
-#ifdef CONFIG_ACPI
-void acpi_gpiochip_add(struct gpio_chip *chip);
-void acpi_gpiochip_remove(struct gpio_chip *chip);
-
-void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
-void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-
-int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
-                                struct acpi_gpio_info *info);
-int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
-                                       struct acpi_gpio_info *info);
-
-struct gpio_desc *acpi_find_gpio(struct device *dev,
-                                const char *con_id,
-                                unsigned int idx,
-                                enum gpiod_flags *dflags,
-                                unsigned long *lookupflags);
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
-                                     const char *propname, int index,
-                                     struct acpi_gpio_info *info);
-
-int acpi_gpio_count(struct device *dev, const char *con_id);
-
-bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
-#else
-static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
-static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
-
-static inline void
-acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
-
-static inline void
-acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
-
-static inline int
-acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
-{
-       return 0;
-}
-static inline int
-acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
-                                   struct acpi_gpio_info *info)
-{
-       return 0;
-}
-
-static inline struct gpio_desc *
-acpi_find_gpio(struct device *dev, const char *con_id,
-              unsigned int idx, enum gpiod_flags *dflags,
-              unsigned long *lookupflags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline struct gpio_desc *
-acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
-                   int index, struct acpi_gpio_info *info)
-{
-       return ERR_PTR(-ENXIO);
-}
-static inline int acpi_gpio_count(struct device *dev, const char *con_id)
-{
-       return -ENODEV;
-}
-
-static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
-                                           const char *con_id)
-{
-       return false;
-}
-#endif
-
 struct gpio_array {
        struct gpio_desc        **desc;
        unsigned int            size;
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
new file mode 100644 (file)
index 0000000..7e99860
--- /dev/null
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 American Megatrends International LLC.
+ *
+ * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#define MAX_NR_SGPIO                   80
+
+#define ASPEED_SGPIO_CTRL              0x54
+
+#define ASPEED_SGPIO_PINS_MASK         GENMASK(9, 6)
+#define ASPEED_SGPIO_CLK_DIV_MASK      GENMASK(31, 16)
+#define ASPEED_SGPIO_ENABLE            BIT(0)
+
+struct aspeed_sgpio {
+       struct gpio_chip chip;
+       struct clk *pclk;
+       spinlock_t lock;
+       void __iomem *base;
+       uint32_t dir_in[3];
+       int irq;
+};
+
+struct aspeed_sgpio_bank {
+       uint16_t    val_regs;
+       uint16_t    rdata_reg;
+       uint16_t    irq_regs;
+       const char  names[4][3];
+};
+
+/*
+ * Note: The "value" register returns the input value when the GPIO is
+ *      configured as an input.
+ *
+ *      The "rdata" register returns the output value when the GPIO is
+ *      configured as an output.
+ */
+static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
+       {
+               .val_regs = 0x0000,
+               .rdata_reg = 0x0070,
+               .irq_regs = 0x0004,
+               .names = { "A", "B", "C", "D" },
+       },
+       {
+               .val_regs = 0x001C,
+               .rdata_reg = 0x0074,
+               .irq_regs = 0x0020,
+               .names = { "E", "F", "G", "H" },
+       },
+       {
+               .val_regs = 0x0038,
+               .rdata_reg = 0x0078,
+               .irq_regs = 0x003C,
+               .names = { "I", "J" },
+       },
+};
+
+enum aspeed_sgpio_reg {
+       reg_val,
+       reg_rdata,
+       reg_irq_enable,
+       reg_irq_type0,
+       reg_irq_type1,
+       reg_irq_type2,
+       reg_irq_status,
+};
+
+#define GPIO_VAL_VALUE      0x00
+#define GPIO_IRQ_ENABLE     0x00
+#define GPIO_IRQ_TYPE0      0x04
+#define GPIO_IRQ_TYPE1      0x08
+#define GPIO_IRQ_TYPE2      0x0C
+#define GPIO_IRQ_STATUS     0x10
+
+static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
+                                    const struct aspeed_sgpio_bank *bank,
+                                    const enum aspeed_sgpio_reg reg)
+{
+       switch (reg) {
+       case reg_val:
+               return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
+       case reg_rdata:
+               return gpio->base + bank->rdata_reg;
+       case reg_irq_enable:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
+       case reg_irq_type0:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
+       case reg_irq_type1:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
+       case reg_irq_type2:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
+       case reg_irq_status:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
+       default:
+               /* acturally if code runs to here, it's an error case */
+               BUG_ON(1);
+       }
+}
+
+#define GPIO_BANK(x)    ((x) >> 5)
+#define GPIO_OFFSET(x)  ((x) & 0x1f)
+#define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
+
+static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
+{
+       unsigned int bank = GPIO_BANK(offset);
+
+       WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
+       return &aspeed_sgpio_banks[bank];
+}
+
+static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_sgpio_bank *bank = to_bank(offset);
+       unsigned long flags;
+       enum aspeed_sgpio_reg reg;
+       bool is_input;
+       int rc = 0;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+       reg = is_input ? reg_val : reg_rdata;
+       rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return rc;
+}
+
+static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_sgpio_bank *bank = to_bank(offset);
+       void __iomem *addr;
+       u32 reg = 0;
+
+       addr = bank_reg(gpio, bank, reg_val);
+       reg = ioread32(addr);
+
+       if (val)
+               reg |= GPIO_BIT(offset);
+       else
+               reg &= ~GPIO_BIT(offset);
+
+       iowrite32(reg, addr);
+}
+
+static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       sgpio_set_value(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+       gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
+       sgpio_set_value(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       int dir_status;
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+       dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return dir_status;
+
+}
+
+static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
+                                       struct aspeed_sgpio **gpio,
+                                       const struct aspeed_sgpio_bank **bank,
+                                       u32 *bit, int *offset)
+{
+       struct aspeed_sgpio *internal;
+
+       *offset = irqd_to_hwirq(d);
+       internal = irq_data_get_irq_chip_data(d);
+       WARN_ON(!internal);
+
+       *gpio = internal;
+       *bank = to_bank(*offset);
+       *bit = GPIO_BIT(*offset);
+}
+
+static void aspeed_sgpio_irq_ack(struct irq_data *d)
+{
+       const struct aspeed_sgpio_bank *bank;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       void __iomem *status_addr;
+       int offset;
+       u32 bit;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+       status_addr = bank_reg(gpio, bank, reg_irq_status);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       iowrite32(bit, status_addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
+{
+       const struct aspeed_sgpio_bank *bank;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       u32 reg, bit;
+       void __iomem *addr;
+       int offset;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+       addr = bank_reg(gpio, bank, reg_irq_enable);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       reg = ioread32(addr);
+       if (set)
+               reg |= bit;
+       else
+               reg &= ~bit;
+
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_mask(struct irq_data *d)
+{
+       aspeed_sgpio_irq_set_mask(d, false);
+}
+
+static void aspeed_sgpio_irq_unmask(struct irq_data *d)
+{
+       aspeed_sgpio_irq_set_mask(d, true);
+}
+
+static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
+{
+       u32 type0 = 0;
+       u32 type1 = 0;
+       u32 type2 = 0;
+       u32 bit, reg;
+       const struct aspeed_sgpio_bank *bank;
+       irq_flow_handler_t handler;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       void __iomem *addr;
+       int offset;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_BOTH:
+               type2 |= bit;
+               /* fall through */
+       case IRQ_TYPE_EDGE_RISING:
+               type0 |= bit;
+               /* fall through */
+       case IRQ_TYPE_EDGE_FALLING:
+               handler = handle_edge_irq;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type0 |= bit;
+               /* fall through */
+       case IRQ_TYPE_LEVEL_LOW:
+               type1 |= bit;
+               handler = handle_level_irq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       addr = bank_reg(gpio, bank, reg_irq_type0);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type0;
+       iowrite32(reg, addr);
+
+       addr = bank_reg(gpio, bank, reg_irq_type1);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type1;
+       iowrite32(reg, addr);
+
+       addr = bank_reg(gpio, bank, reg_irq_type2);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type2;
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       irq_set_handler_locked(d, handler);
+
+       return 0;
+}
+
+static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct irq_chip *ic = irq_desc_get_chip(desc);
+       struct aspeed_sgpio *data = gpiochip_get_data(gc);
+       unsigned int i, p, girq;
+       unsigned long reg;
+
+       chained_irq_enter(ic, desc);
+
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
+
+               reg = ioread32(bank_reg(data, bank, reg_irq_status));
+
+               for_each_set_bit(p, &reg, 32) {
+                       girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
+                       generic_handle_irq(girq);
+               }
+
+       }
+
+       chained_irq_exit(ic, desc);
+}
+
+static struct irq_chip aspeed_sgpio_irqchip = {
+       .name       = "aspeed-sgpio",
+       .irq_ack    = aspeed_sgpio_irq_ack,
+       .irq_mask   = aspeed_sgpio_irq_mask,
+       .irq_unmask = aspeed_sgpio_irq_unmask,
+       .irq_set_type   = aspeed_sgpio_set_type,
+};
+
+static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
+                                  struct platform_device *pdev)
+{
+       int rc, i;
+       const struct aspeed_sgpio_bank *bank;
+       struct gpio_irq_chip *irq;
+
+       rc = platform_get_irq(pdev, 0);
+       if (rc < 0)
+               return rc;
+
+       gpio->irq = rc;
+
+       /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               bank =  &aspeed_sgpio_banks[i];
+               /* disable irq enable bits */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
+               /* clear status bits */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
+       }
+
+       irq = &gpio->chip.irq;
+       irq->chip = &aspeed_sgpio_irqchip;
+       irq->handler = handle_bad_irq;
+       irq->default_type = IRQ_TYPE_NONE;
+       irq->parent_handler = aspeed_sgpio_irq_handler;
+       irq->parent_handler_data = gpio;
+       irq->parents = &gpio->irq;
+       irq->num_parents = 1;
+
+       /* set IRQ settings and Enable Interrupt */
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               bank = &aspeed_sgpio_banks[i];
+               /* set falling or level-low irq */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
+               /* trigger type is edge */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
+               /* dual edge trigger mode. */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
+               /* enable irq */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+       }
+
+       return 0;
+}
+
+static const struct of_device_id aspeed_sgpio_of_table[] = {
+       { .compatible = "aspeed,ast2400-sgpio" },
+       { .compatible = "aspeed,ast2500-sgpio" },
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
+
+static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+{
+       struct aspeed_sgpio *gpio;
+       u32 nr_gpios, sgpio_freq, sgpio_clk_div;
+       int rc;
+       unsigned long apb_freq;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       gpio->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gpio->base))
+               return PTR_ERR(gpio->base);
+
+       rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Could not read ngpios property\n");
+               return -EINVAL;
+       } else if (nr_gpios > MAX_NR_SGPIO) {
+               dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
+                       MAX_NR_SGPIO, nr_gpios);
+               return -EINVAL;
+       }
+
+       rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Could not read bus-frequency property\n");
+               return -EINVAL;
+       }
+
+       gpio->pclk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(gpio->pclk)) {
+               dev_err(&pdev->dev, "devm_clk_get failed\n");
+               return PTR_ERR(gpio->pclk);
+       }
+
+       apb_freq = clk_get_rate(gpio->pclk);
+
+       /*
+        * From the datasheet,
+        *      SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
+        *      period = 2 * (GPIO254[31:16] + 1) / PCLK
+        *      frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
+        *      frequency = PCLK / (2 * (GPIO254[31:16] + 1))
+        *      frequency * 2 * (GPIO254[31:16] + 1) = PCLK
+        *      GPIO254[31:16] = PCLK / (frequency * 2) - 1
+        */
+       if (sgpio_freq == 0)
+               return -EINVAL;
+
+       sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
+
+       if (sgpio_clk_div > (1 << 16) - 1)
+               return -EINVAL;
+
+       iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
+                 FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
+                 ASPEED_SGPIO_ENABLE,
+                 gpio->base + ASPEED_SGPIO_CTRL);
+
+       spin_lock_init(&gpio->lock);
+
+       gpio->chip.parent = &pdev->dev;
+       gpio->chip.ngpio = nr_gpios;
+       gpio->chip.direction_input = aspeed_sgpio_dir_in;
+       gpio->chip.direction_output = aspeed_sgpio_dir_out;
+       gpio->chip.get_direction = aspeed_sgpio_get_direction;
+       gpio->chip.request = NULL;
+       gpio->chip.free = NULL;
+       gpio->chip.get = aspeed_sgpio_get;
+       gpio->chip.set = aspeed_sgpio_set;
+       gpio->chip.set_config = NULL;
+       gpio->chip.label = dev_name(&pdev->dev);
+       gpio->chip.base = -1;
+
+       /* set all SGPIO pins as input (1). */
+       memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
+
+       aspeed_sgpio_setup_irqs(gpio, pdev);
+
+       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static struct platform_driver aspeed_sgpio_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = aspeed_sgpio_of_table,
+       },
+};
+
+module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
+MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
+MODULE_LICENSE("GPL");
index 9b384a9..3e35a8f 100644 (file)
@@ -574,6 +574,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
        { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
+       { 0x1002, 0x699f, 0x1028, 0x0814, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x17AA, 0x3806, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0, 0, 0, 0, 0 },
index 4e4094f..8b26c97 100644 (file)
@@ -1143,6 +1143,9 @@ static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p,
        num_deps = chunk->length_dw * 4 /
                sizeof(struct drm_amdgpu_cs_chunk_sem);
 
+       if (p->post_deps)
+               return -EINVAL;
+
        p->post_deps = kmalloc_array(num_deps, sizeof(*p->post_deps),
                                     GFP_KERNEL);
        p->num_post_deps = 0;
@@ -1166,8 +1169,7 @@ static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p,
 
 
 static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p,
-                                                     struct amdgpu_cs_chunk
-                                                     *chunk)
+                                                     struct amdgpu_cs_chunk *chunk)
 {
        struct drm_amdgpu_cs_chunk_syncobj *syncobj_deps;
        unsigned num_deps;
@@ -1177,6 +1179,9 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p
        num_deps = chunk->length_dw * 4 /
                sizeof(struct drm_amdgpu_cs_chunk_syncobj);
 
+       if (p->post_deps)
+               return -EINVAL;
+
        p->post_deps = kmalloc_array(num_deps, sizeof(*p->post_deps),
                                     GFP_KERNEL);
        p->num_post_deps = 0;
index f539a2a..7398b48 100644 (file)
@@ -534,21 +534,24 @@ int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx,
                               struct drm_sched_entity *entity)
 {
        struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
-       unsigned idx = centity->sequence & (amdgpu_sched_jobs - 1);
-       struct dma_fence *other = centity->fences[idx];
+       struct dma_fence *other;
+       unsigned idx;
+       long r;
 
-       if (other) {
-               signed long r;
-               r = dma_fence_wait(other, true);
-               if (r < 0) {
-                       if (r != -ERESTARTSYS)
-                               DRM_ERROR("Error (%ld) waiting for fence!\n", r);
+       spin_lock(&ctx->ring_lock);
+       idx = centity->sequence & (amdgpu_sched_jobs - 1);
+       other = dma_fence_get(centity->fences[idx]);
+       spin_unlock(&ctx->ring_lock);
 
-                       return r;
-               }
-       }
+       if (!other)
+               return 0;
 
-       return 0;
+       r = dma_fence_wait(other, true);
+       if (r < 0 && r != -ERESTARTSYS)
+               DRM_ERROR("Error (%ld) waiting for fence!\n", r);
+
+       dma_fence_put(other);
+       return r;
 }
 
 void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
index 1cf639a..c066e1d 100644 (file)
@@ -596,14 +596,18 @@ static void gfx_v9_0_check_if_need_gfxoff(struct amdgpu_device *adev)
        case CHIP_VEGA20:
                break;
        case CHIP_RAVEN:
-               if (adev->rev_id >= 0x8 || adev->pdev->device == 0x15d8)
-                       break;
-               if ((adev->gfx.rlc_fw_version != 106 &&
-                    adev->gfx.rlc_fw_version < 531) ||
-                   (adev->gfx.rlc_fw_version == 53815) ||
-                   (adev->gfx.rlc_feature_version < 1) ||
-                   !adev->gfx.rlc.is_rlc_v2_1)
+               if (!(adev->rev_id >= 0x8 || adev->pdev->device == 0x15d8)
+                       &&((adev->gfx.rlc_fw_version != 106 &&
+                            adev->gfx.rlc_fw_version < 531) ||
+                           (adev->gfx.rlc_fw_version == 53815) ||
+                           (adev->gfx.rlc_feature_version < 1) ||
+                           !adev->gfx.rlc.is_rlc_v2_1))
                        adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
+
+               if (adev->pm.pp_feature & PP_GFXOFF_MASK)
+                       adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
+                               AMD_PG_SUPPORT_CP |
+                               AMD_PG_SUPPORT_RLC_SMU_HS;
                break;
        default:
                break;
@@ -4869,7 +4873,7 @@ static void gfx_v9_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid)
        value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
        value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
        value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
-       WREG32(mmSQ_CMD, value);
+       WREG32_SOC15(GC, 0, mmSQ_CMD, value);
 }
 
 static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
index 662612f..9922bce 100644 (file)
@@ -552,7 +552,6 @@ static int nv_common_early_init(void *handle)
                        AMD_CG_SUPPORT_BIF_LS;
                adev->pg_flags = AMD_PG_SUPPORT_VCN |
                        AMD_PG_SUPPORT_VCN_DPG |
-                       AMD_PG_SUPPORT_MMHUB |
                        AMD_PG_SUPPORT_ATHUB;
                adev->external_rev_id = adev->rev_id + 0x1;
                break;
index 2326541..04fbf05 100644 (file)
@@ -992,11 +992,6 @@ static int soc15_common_early_init(void *handle)
 
                        adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN;
                }
-
-               if (adev->pm.pp_feature & PP_GFXOFF_MASK)
-                       adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
-                               AMD_PG_SUPPORT_CP |
-                               AMD_PG_SUPPORT_RLC_SMU_HS;
                break;
        default:
                /* FIXME: not supported yet */
index 4a29f72..45be7a2 100644 (file)
@@ -3131,13 +3131,25 @@ static enum dc_color_depth
 convert_color_depth_from_display_info(const struct drm_connector *connector,
                                      const struct drm_connector_state *state)
 {
-       uint32_t bpc = connector->display_info.bpc;
+       uint8_t bpc = (uint8_t)connector->display_info.bpc;
+
+       /* Assume 8 bpc by default if no bpc is specified. */
+       bpc = bpc ? bpc : 8;
 
        if (!state)
                state = connector->state;
 
        if (state) {
-               bpc = state->max_bpc;
+               /*
+                * Cap display bpc based on the user requested value.
+                *
+                * The value for state->max_bpc may not correctly updated
+                * depending on when the connector gets added to the state
+                * or if this was called outside of atomic check, so it
+                * can't be used directly.
+                */
+               bpc = min(bpc, state->max_requested_bpc);
+
                /* Round down to the nearest even number. */
                bpc = bpc - (bpc & 1);
        }
index fa20201..cbc480a 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/mm.h>
 
 #include "dm_services.h"
 
@@ -1171,8 +1172,8 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
 
 struct dc_state *dc_create_state(struct dc *dc)
 {
-       struct dc_state *context = kzalloc(sizeof(struct dc_state),
-                                          GFP_KERNEL);
+       struct dc_state *context = kvzalloc(sizeof(struct dc_state),
+                                           GFP_KERNEL);
 
        if (!context)
                return NULL;
@@ -1192,11 +1193,11 @@ struct dc_state *dc_create_state(struct dc *dc)
 struct dc_state *dc_copy_state(struct dc_state *src_ctx)
 {
        int i, j;
-       struct dc_state *new_ctx = kmemdup(src_ctx,
-                       sizeof(struct dc_state), GFP_KERNEL);
+       struct dc_state *new_ctx = kvmalloc(sizeof(struct dc_state), GFP_KERNEL);
 
        if (!new_ctx)
                return NULL;
+       memcpy(new_ctx, src_ctx, sizeof(struct dc_state));
 
        for (i = 0; i < MAX_PIPES; i++) {
                        struct pipe_ctx *cur_pipe = &new_ctx->res_ctx.pipe_ctx[i];
@@ -1230,7 +1231,7 @@ static void dc_state_free(struct kref *kref)
 {
        struct dc_state *context = container_of(kref, struct dc_state, refcount);
        dc_resource_state_destruct(context);
-       kfree(context);
+       kvfree(context);
 }
 
 void dc_release_state(struct dc_state *context)
index f27c6fb..90c4e87 100644 (file)
@@ -2101,7 +2101,11 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr,
        if (ret)
                return ret;
 
-       *query = metrics_table.CurrSocketPower << 8;
+       /* For the 40.46 release, they changed the value name */
+       if (hwmgr->smu_version == 0x282e00)
+               *query = metrics_table.AverageSocketPower << 8;
+       else
+               *query = metrics_table.CurrSocketPower << 8;
 
        return ret;
 }
@@ -2349,12 +2353,16 @@ static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr)
                data->dpm_table.soc_table.dpm_state.soft_max_level =
                data->dpm_table.soc_table.dpm_levels[soft_level].value;
 
-       ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
+       ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload boot level to highest!",
                        return ret);
 
-       ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
+       ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload dpm max level to highest!",
                        return ret);
@@ -2387,12 +2395,16 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
                data->dpm_table.soc_table.dpm_state.soft_max_level =
                data->dpm_table.soc_table.dpm_levels[soft_level].value;
 
-       ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
+       ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload boot level to highest!",
                        return ret);
 
-       ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
+       ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload dpm max level to highest!",
                        return ret);
@@ -2403,14 +2415,54 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr)
 
 static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
 {
+       struct vega20_hwmgr *data =
+                       (struct vega20_hwmgr *)(hwmgr->backend);
+       uint32_t soft_min_level, soft_max_level;
        int ret = 0;
 
-       ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF);
+       /* gfxclk soft min/max settings */
+       soft_min_level =
+               vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table));
+       soft_max_level =
+               vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table));
+
+       data->dpm_table.gfx_table.dpm_state.soft_min_level =
+               data->dpm_table.gfx_table.dpm_levels[soft_min_level].value;
+       data->dpm_table.gfx_table.dpm_state.soft_max_level =
+               data->dpm_table.gfx_table.dpm_levels[soft_max_level].value;
+
+       /* uclk soft min/max settings */
+       soft_min_level =
+               vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table));
+       soft_max_level =
+               vega20_find_highest_dpm_level(&(data->dpm_table.mem_table));
+
+       data->dpm_table.mem_table.dpm_state.soft_min_level =
+               data->dpm_table.mem_table.dpm_levels[soft_min_level].value;
+       data->dpm_table.mem_table.dpm_state.soft_max_level =
+               data->dpm_table.mem_table.dpm_levels[soft_max_level].value;
+
+       /* socclk soft min/max settings */
+       soft_min_level =
+               vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table));
+       soft_max_level =
+               vega20_find_highest_dpm_level(&(data->dpm_table.soc_table));
+
+       data->dpm_table.soc_table.dpm_state.soft_min_level =
+               data->dpm_table.soc_table.dpm_levels[soft_min_level].value;
+       data->dpm_table.soc_table.dpm_state.soft_max_level =
+               data->dpm_table.soc_table.dpm_levels[soft_max_level].value;
+
+       ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload DPM Bootup Levels!",
                        return ret);
 
-       ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF);
+       ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK |
+                                                FEATURE_DPM_UCLK_MASK |
+                                                FEATURE_DPM_SOCCLK_MASK);
        PP_ASSERT_WITH_CODE(!ret,
                        "Failed to upload DPM Max Levels!",
                        return ret);
index a0f52c8..a78b2e2 100644 (file)
@@ -907,8 +907,6 @@ struct smu_funcs
        ((smu)->funcs->register_irq_handler ? (smu)->funcs->register_irq_handler(smu) : 0)
 #define smu_set_azalia_d3_pme(smu) \
        ((smu)->funcs->set_azalia_d3_pme ? (smu)->funcs->set_azalia_d3_pme((smu)) : 0)
-#define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \
-       ((smu)->ppt_funcs->get_uclk_dpm_states ? (smu)->ppt_funcs->get_uclk_dpm_states((smu), (clocks_in_khz), (num_states)) : 0)
 #define smu_get_max_sustainable_clocks_by_dc(smu, max_clocks) \
        ((smu)->funcs->get_max_sustainable_clocks_by_dc ? (smu)->funcs->get_max_sustainable_clocks_by_dc((smu), (max_clocks)) : 0)
 #define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \
index 5fde5cf..5309796 100644 (file)
@@ -326,7 +326,8 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu)
        struct amdgpu_device *adev = smu->adev;
        const struct smc_firmware_header_v1_0 *hdr;
        int ret, index;
-       uint32_t size;
+       uint32_t size = 0;
+       uint16_t atom_table_size;
        uint8_t frev, crev;
        void *table;
        uint16_t version_major, version_minor;
@@ -354,10 +355,11 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu)
                index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
                                                    powerplayinfo);
 
-               ret = smu_get_atom_data_table(smu, index, (uint16_t *)&size, &frev, &crev,
+               ret = smu_get_atom_data_table(smu, index, &atom_table_size, &frev, &crev,
                                              (uint8_t **)&table);
                if (ret)
                        return ret;
+               size = atom_table_size;
        }
 
        if (!smu->smu_table.power_play_table)
index dd6fd1c..6a14497 100644 (file)
@@ -3050,6 +3050,7 @@ static int vega20_get_fan_speed_percent(struct smu_context *smu,
 
 static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value)
 {
+       uint32_t smu_version;
        int ret = 0;
        SmuMetrics_t metrics;
 
@@ -3060,7 +3061,15 @@ static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value)
        if (ret)
                return ret;
 
-       *value = metrics.CurrSocketPower << 8;
+       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (ret)
+               return ret;
+
+       /* For the 40.46 release, they changed the value name */
+       if (smu_version == 0x282e00)
+               *value = metrics.AverageSocketPower << 8;
+       else
+               *value = metrics.CurrSocketPower << 8;
 
        return 0;
 }
index 5a11898..9d4d507 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/iommu.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #ifdef CONFIG_DEBUG_FS
@@ -126,7 +127,7 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
        pipe->of_output_port =
                of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
 
-       pipe->of_node = np;
+       pipe->of_node = of_node_get(np);
 
        return 0;
 }
@@ -143,6 +144,12 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
                return mdev->irq;
        }
 
+       /* Get the optional framebuffer memory resource */
+       ret = of_reserved_mem_device_init(dev);
+       if (ret && ret != -ENODEV)
+               return ret;
+       ret = 0;
+
        for_each_available_child_of_node(np, child) {
                if (of_node_cmp(child->name, "pipeline") == 0) {
                        ret = komeda_parse_pipe_dt(mdev, child);
@@ -289,6 +296,8 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
 
        mdev->n_pipelines = 0;
 
+       of_reserved_mem_device_release(dev);
+
        if (funcs && funcs->cleanup)
                funcs->cleanup(mdev);
 
index cd4d9f5..c9a1edb 100644 (file)
@@ -35,6 +35,25 @@ komeda_get_format_caps(struct komeda_format_caps_table *table,
        return NULL;
 }
 
+u32 komeda_get_afbc_format_bpp(const struct drm_format_info *info, u64 modifier)
+{
+       u32 bpp;
+
+       switch (info->format) {
+       case DRM_FORMAT_YUV420_8BIT:
+               bpp = 12;
+               break;
+       case DRM_FORMAT_YUV420_10BIT:
+               bpp = 15;
+               break;
+       default:
+               bpp = info->cpp[0] * 8;
+               break;
+       }
+
+       return bpp;
+}
+
 /* Two assumptions
  * 1. RGB always has YTR
  * 2. Tiled RGB always has SC
index 3631910..32273cf 100644 (file)
@@ -97,6 +97,9 @@ const struct komeda_format_caps *
 komeda_get_format_caps(struct komeda_format_caps_table *table,
                       u32 fourcc, u64 modifier);
 
+u32 komeda_get_afbc_format_bpp(const struct drm_format_info *info,
+                              u64 modifier);
+
 u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
                                  u32 layer_type, u32 *n_fmts);
 
index 3b0a70e..1b01a62 100644 (file)
@@ -43,7 +43,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
        struct drm_framebuffer *fb = &kfb->base;
        const struct drm_format_info *info = fb->format;
        struct drm_gem_object *obj;
-       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks;
+       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
        u64 min_size;
 
        obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
@@ -88,8 +88,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
        kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
                                    alignment_header);
 
+       bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
        kfb->afbc_size = kfb->offset_payload + n_blocks *
-                        ALIGN(info->cpp[0] * AFBC_SUPERBLK_PIXELS,
+                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
                               AFBC_SUPERBLK_ALIGNMENT);
        min_size = kfb->afbc_size + fb->offsets[0];
        if (min_size > obj->size) {
index 419a8b0..69d9e26 100644 (file)
@@ -14,6 +14,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_irq.h>
+#include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
 #include "komeda_dev.h"
@@ -146,7 +147,6 @@ static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc,
        struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_st);
        struct komeda_plane_state *kplane_st;
        struct drm_plane_state *plane_st;
-       struct drm_framebuffer *fb;
        struct drm_plane *plane;
        struct list_head zorder_list;
        int order = 0, err;
@@ -172,7 +172,6 @@ static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc,
 
        list_for_each_entry(kplane_st, &zorder_list, zlist_node) {
                plane_st = &kplane_st->base;
-               fb = plane_st->fb;
                plane = plane_st->plane;
 
                plane_st->normalized_zpos = order++;
@@ -205,7 +204,7 @@ static int komeda_kms_check(struct drm_device *dev,
                            struct drm_atomic_state *state)
 {
        struct drm_crtc *crtc;
-       struct drm_crtc_state *old_crtc_st, *new_crtc_st;
+       struct drm_crtc_state *new_crtc_st;
        int i, err;
 
        err = drm_atomic_helper_check_modeset(dev, state);
@@ -216,7 +215,7 @@ static int komeda_kms_check(struct drm_device *dev,
         * so need to add all affected_planes (even unchanged) to
         * drm_atomic_state.
         */
-       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_st, new_crtc_st, i) {
+       for_each_new_crtc_in_state(state, crtc, new_crtc_st, i) {
                err = drm_atomic_add_affected_planes(state, crtc);
                if (err)
                        return err;
@@ -307,24 +306,33 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
                               komeda_kms_irq_handler, IRQF_SHARED,
                               drm->driver->name, drm);
        if (err)
-               goto cleanup_mode_config;
+               goto free_component_binding;
 
        err = mdev->funcs->enable_irq(mdev);
        if (err)
-               goto cleanup_mode_config;
+               goto free_component_binding;
 
        drm->irq_enabled = true;
 
+       drm_kms_helper_poll_init(drm);
+
        err = drm_dev_register(drm, 0);
        if (err)
-               goto cleanup_mode_config;
+               goto free_interrupts;
 
        return kms;
 
-cleanup_mode_config:
+free_interrupts:
+       drm_kms_helper_poll_fini(drm);
        drm->irq_enabled = false;
+       mdev->funcs->disable_irq(mdev);
+free_component_binding:
+       component_unbind_all(mdev->dev, drm);
+cleanup_mode_config:
        drm_mode_config_cleanup(drm);
        komeda_kms_cleanup_private_objs(kms);
+       drm->dev_private = NULL;
+       drm_dev_put(drm);
 free_kms:
        kfree(kms);
        return ERR_PTR(err);
@@ -335,12 +343,14 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
        struct drm_device *drm = &kms->base;
        struct komeda_dev *mdev = drm->dev_private;
 
+       drm_dev_unregister(drm);
+       drm_kms_helper_poll_fini(drm);
+       drm_atomic_helper_shutdown(drm);
        drm->irq_enabled = false;
        mdev->funcs->disable_irq(mdev);
-       drm_dev_unregister(drm);
        component_unbind_all(mdev->dev, drm);
-       komeda_kms_cleanup_private_objs(kms);
        drm_mode_config_cleanup(drm);
+       komeda_kms_cleanup_private_objs(kms);
        drm->dev_private = NULL;
        drm_dev_put(drm);
 }
index a90bcbb..14b6831 100644 (file)
@@ -480,6 +480,7 @@ void komeda_pipeline_dump_register(struct komeda_pipeline *pipe,
                                   struct seq_file *sf);
 
 /* component APIs */
+extern __printf(10, 11)
 struct komeda_component *
 komeda_component_add(struct komeda_pipeline *pipe,
                     size_t comp_sz, u32 id, u32 hw_id,
index 617e1f7..2851cac 100644 (file)
@@ -148,7 +148,7 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,
        if (!kcrtc->master->wb_layer)
                return 0;
 
-       kwb_conn = kzalloc(sizeof(*wb_conn), GFP_KERNEL);
+       kwb_conn = kzalloc(sizeof(*kwb_conn), GFP_KERNEL);
        if (!kwb_conn)
                return -ENOMEM;
 
index 4c7e31c..a5d1494 100644 (file)
@@ -131,8 +131,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 
 
        /* Enable extended register access */
-       ast_enable_mmio(dev);
        ast_open_key(ast);
+       ast_enable_mmio(dev);
 
        /* Find out whether P2A works or whether to use device-tree */
        ast_detect_config_mode(dev, &scu_rev);
@@ -576,6 +576,9 @@ void ast_driver_unload(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
 
+       /* enable standard VGA decode */
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
+
        ast_release_firmware(dev);
        kfree(ast->dp501_fw_addr);
        ast_mode_fini(dev);
index ffccbef..a1cb020 100644 (file)
@@ -604,7 +604,7 @@ static int ast_crtc_mode_set(struct drm_crtc *crtc,
                return -EINVAL;
        ast_open_key(ast);
 
-       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06);
 
        ast_set_std_reg(crtc, adjusted_mode, &vbios_mode);
        ast_set_crtc_reg(crtc, adjusted_mode, &vbios_mode);
index f7d4213..c1d1ac5 100644 (file)
@@ -46,7 +46,7 @@ void ast_enable_mmio(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
 
-       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06);
 }
 
 
index b0369e6..c814bce 100644 (file)
@@ -1454,6 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
 }
 
 static int drm_mode_parse_cmdline_extra(const char *str, int length,
+                                       bool freestanding,
                                        const struct drm_connector *connector,
                                        struct drm_cmdline_mode *mode)
 {
@@ -1462,9 +1463,15 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,
        for (i = 0; i < length; i++) {
                switch (str[i]) {
                case 'i':
+                       if (freestanding)
+                               return -EINVAL;
+
                        mode->interlace = true;
                        break;
                case 'm':
+                       if (freestanding)
+                               return -EINVAL;
+
                        mode->margins = true;
                        break;
                case 'D':
@@ -1542,6 +1549,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
                        if (extras) {
                                int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
                                                                       1,
+                                                                      false,
                                                                       connector,
                                                                       mode);
                                if (ret)
@@ -1669,6 +1677,22 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
        return 0;
 }
 
+static const char * const drm_named_modes_whitelist[] = {
+       "NTSC",
+       "PAL",
+};
+
+static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
+               if (!strncmp(mode, drm_named_modes_whitelist[i], size))
+                       return true;
+
+       return false;
+}
+
 /**
  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
  * @mode_option: optional per connector mode option
@@ -1725,16 +1749,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
         * bunch of things:
         *   - We need to make sure that the first character (which
         *     would be our resolution in X) is a digit.
-        *   - However, if the X resolution is missing, then we end up
-        *     with something like x<yres>, with our first character
-        *     being an alpha-numerical character, which would be
-        *     considered a named mode.
+        *   - If not, then it's either a named mode or a force on/off.
+        *     To distinguish between the two, we need to run the
+        *     extra parsing function, and if not, then we consider it
+        *     a named mode.
         *
         * If this isn't enough, we should add more heuristics here,
         * and matching unit-tests.
         */
-       if (!isdigit(name[0]) && name[0] != 'x')
+       if (!isdigit(name[0]) && name[0] != 'x') {
+               unsigned int namelen = strlen(name);
+
+               /*
+                * Only the force on/off options can be in that case,
+                * and they all take a single character.
+                */
+               if (namelen == 1) {
+                       ret = drm_mode_parse_cmdline_extra(name, namelen, true,
+                                                          connector, mode);
+                       if (!ret)
+                               return true;
+               }
+
                named_mode = true;
+       }
 
        /* Try to locate the bpp and refresh specifiers, if any */
        bpp_ptr = strchr(name, '-');
@@ -1772,6 +1810,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
        if (named_mode) {
                if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
                        return false;
+
+               if (!drm_named_mode_is_in_whitelist(name, mode_end))
+                       return false;
+
                strscpy(mode->name, name, mode_end + 1);
        } else {
                ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
@@ -1811,7 +1853,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
            extra_ptr != options_ptr) {
                int len = strlen(name) - (extra_ptr - name);
 
-               ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+               ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
                                                   connector, mode);
                if (ret)
                        return false;
index 7925a17..1cb1fa7 100644 (file)
@@ -1465,8 +1465,8 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
        else if (intel_crtc_has_dp_encoder(pipe_config))
                dotclock = intel_dotclock_calculate(pipe_config->port_clock,
                                                    &pipe_config->dp_m_n);
-       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36)
-               dotclock = pipe_config->port_clock * 2 / 3;
+       else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp > 24)
+               dotclock = pipe_config->port_clock * 24 / pipe_config->pipe_bpp;
        else
                dotclock = pipe_config->port_clock;
 
index 60652eb..8aa6a31 100644 (file)
@@ -128,7 +128,15 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
        limits.max_lane_count = intel_dp_max_lane_count(intel_dp);
 
        limits.min_bpp = intel_dp_min_bpp(pipe_config);
-       limits.max_bpp = pipe_config->pipe_bpp;
+       /*
+        * FIXME: If all the streams can't fit into the link with
+        * their current pipe_bpp we should reduce pipe_bpp across
+        * the board until things start to fit. Until then we
+        * limit to <= 8bpc since that's what was hardcoded for all
+        * MST streams previously. This hack should be removed once
+        * we have the proper retry logic in place.
+        */
+       limits.max_bpp = min(pipe_config->pipe_bpp, 24);
 
        intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits);
 
@@ -539,7 +547,15 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
 
        intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
-       drm_connector_attach_max_bpc_property(connector, 6, 12);
+
+       /*
+        * Reuse the prop from the SST connector because we're
+        * not allowed to create new props after device registration.
+        */
+       connector->max_bpc_property =
+               intel_dp->attached_connector->base.max_bpc_property;
+       if (connector->max_bpc_property)
+               drm_connector_attach_max_bpc_property(connector, 6, 12);
 
        return connector;
 
index ffec807..f413904 100644 (file)
@@ -541,7 +541,7 @@ static void intel_configure_pps_for_dsc_encoder(struct intel_encoder *encoder,
        pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) |
                DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances);
        DRM_INFO("PPS2 = 0x%08x\n", pps_val);
-       if (encoder->type == INTEL_OUTPUT_EDP) {
+       if (cpu_transcoder == TRANSCODER_EDP) {
                I915_WRITE(DSCA_PICTURE_PARAMETER_SET_2, pps_val);
                /*
                 * If 2 VDSC instances are needed, configure PPS for second
index 2caa594..528b616 100644 (file)
@@ -664,15 +664,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj,
 
        for_each_sgt_page(page, sgt_iter, pages) {
                if (obj->mm.dirty)
-                       /*
-                        * As this may not be anonymous memory (e.g. shmem)
-                        * but exist on a real mapping, we have to lock
-                        * the page in order to dirty it -- holding
-                        * the page reference is not sufficient to
-                        * prevent the inode from being truncated.
-                        * Play safe and take the lock.
-                        */
-                       set_page_dirty_lock(page);
+                       set_page_dirty(page);
 
                mark_page_accessed(page);
                put_page(page);
index 98dfb08..99e8242 100644 (file)
@@ -308,11 +308,6 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine,
                          FLOW_CONTROL_ENABLE |
                          PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
 
-       /* Syncing dependencies between camera and graphics:skl,bxt,kbl */
-       if (!IS_COFFEELAKE(i915))
-               WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
-                                 GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
-
        /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */
        /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */
        WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
index 9f3fd7d..75baff6 100644 (file)
@@ -1528,9 +1528,9 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu, int ring_id,
                        if (!intel_gvt_ggtt_validate_range(vgpu,
                                workload->wa_ctx.indirect_ctx.guest_gma,
                                workload->wa_ctx.indirect_ctx.size)) {
-                               kmem_cache_free(s->workloads, workload);
                                gvt_vgpu_err("invalid wa_ctx at: 0x%lx\n",
                                    workload->wa_ctx.indirect_ctx.guest_gma);
+                               kmem_cache_free(s->workloads, workload);
                                return ERR_PTR(-EINVAL);
                        }
                }
@@ -1542,9 +1542,9 @@ intel_vgpu_create_workload(struct intel_vgpu *vgpu, int ring_id,
                        if (!intel_gvt_ggtt_validate_range(vgpu,
                                workload->wa_ctx.per_ctx.guest_gma,
                                CACHELINE_BYTES)) {
-                               kmem_cache_free(s->workloads, workload);
                                gvt_vgpu_err("invalid per_ctx at: 0x%lx\n",
                                        workload->wa_ctx.per_ctx.guest_gma);
+                               kmem_cache_free(s->workloads, workload);
                                return ERR_PTR(-EINVAL);
                        }
                }
index f62e339..bac1ee9 100644 (file)
@@ -1598,6 +1598,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 
        pci_set_master(pdev);
 
+       /*
+        * We don't have a max segment size, so set it to the max so sg's
+        * debugging layer doesn't complain
+        */
+       dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+
        /* overlay on gen2 is broken and can't address above 1G */
        if (IS_GEN(dev_priv, 2)) {
                ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(30));
index 94d3992..724627a 100644 (file)
@@ -101,6 +101,9 @@ static struct _balloon_info_ bl_info;
 static void vgt_deballoon_space(struct i915_ggtt *ggtt,
                                struct drm_mm_node *node)
 {
+       if (!drm_mm_node_allocated(node))
+               return;
+
        DRM_DEBUG_DRIVER("deballoon space: range [0x%llx - 0x%llx] %llu KiB.\n",
                         node->start,
                         node->start + node->size,
index 1d58f7e..f119798 100644 (file)
@@ -829,7 +829,7 @@ struct intel_crtc_state {
 
        /*
         * Frequence the dpll for the port should run at. Differs from the
-        * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also
+        * adjusted dotclock e.g. for DP or 10/12bpc hdmi mode. This is also
         * already multiplied by pixel_multiplier.
         */
        int port_clock;
index e9f9e9f..6381652 100644 (file)
@@ -656,10 +656,9 @@ static int ingenic_drm_probe(struct platform_device *pdev)
                return ret;
        }
 
-       if (panel) {
+       if (panel)
                bridge = devm_drm_panel_bridge_add(dev, panel,
-                                                  DRM_MODE_CONNECTOR_Unknown);
-       }
+                                                  DRM_MODE_CONNECTOR_DPI);
 
        priv->dma_hwdesc = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc),
                                              &priv->dma_hwdesc_phys,
index 477c0f7..b609dc0 100644 (file)
@@ -342,7 +342,7 @@ int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns)
        timeout = drm_timeout_abs_to_jiffies(timeout_ns);
 
        ret = drm_gem_reservation_object_wait(file, handle, write, timeout);
-       if (ret == 0)
+       if (ret == -ETIME)
                ret = timeout ? -ETIMEDOUT : -EBUSY;
 
        return ret;
index 95fdbd0..945bc20 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
 
 #include "mtk_drm_crtc.h"
 #include "mtk_drm_ddp.h"
@@ -213,6 +214,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
        struct mtk_drm_private *private = drm->dev_private;
        struct platform_device *pdev;
        struct device_node *np;
+       struct device *dma_dev;
        int ret;
 
        if (!iommu_present(&platform_bus_type))
@@ -275,7 +277,29 @@ static int mtk_drm_kms_init(struct drm_device *drm)
                goto err_component_unbind;
        }
 
-       private->dma_dev = &pdev->dev;
+       dma_dev = &pdev->dev;
+       private->dma_dev = dma_dev;
+
+       /*
+        * Configure the DMA segment size to make sure we get contiguous IOVA
+        * when importing PRIME buffers.
+        */
+       if (!dma_dev->dma_parms) {
+               private->dma_parms_allocated = true;
+               dma_dev->dma_parms =
+                       devm_kzalloc(drm->dev, sizeof(*dma_dev->dma_parms),
+                                    GFP_KERNEL);
+       }
+       if (!dma_dev->dma_parms) {
+               ret = -ENOMEM;
+               goto err_component_unbind;
+       }
+
+       ret = dma_set_max_seg_size(dma_dev, (unsigned int)DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(dma_dev, "Failed to set DMA segment size\n");
+               goto err_unset_dma_parms;
+       }
 
        /*
         * We don't use the drm_irq_install() helpers provided by the DRM
@@ -285,13 +309,16 @@ static int mtk_drm_kms_init(struct drm_device *drm)
        drm->irq_enabled = true;
        ret = drm_vblank_init(drm, MAX_CRTC);
        if (ret < 0)
-               goto err_component_unbind;
+               goto err_unset_dma_parms;
 
        drm_kms_helper_poll_init(drm);
        drm_mode_config_reset(drm);
 
        return 0;
 
+err_unset_dma_parms:
+       if (private->dma_parms_allocated)
+               dma_dev->dma_parms = NULL;
 err_component_unbind:
        component_unbind_all(drm->dev, drm);
 err_config_cleanup:
@@ -302,9 +329,14 @@ err_config_cleanup:
 
 static void mtk_drm_kms_deinit(struct drm_device *drm)
 {
+       struct mtk_drm_private *private = drm->dev_private;
+
        drm_kms_helper_poll_fini(drm);
        drm_atomic_helper_shutdown(drm);
 
+       if (private->dma_parms_allocated)
+               private->dma_dev->dma_parms = NULL;
+
        component_unbind_all(drm->dev, drm);
        drm_mode_config_cleanup(drm);
 }
@@ -320,6 +352,18 @@ static const struct file_operations mtk_drm_fops = {
        .compat_ioctl = drm_compat_ioctl,
 };
 
+/*
+ * We need to override this because the device used to import the memory is
+ * not dev->dev, as drm_gem_prime_import() expects.
+ */
+struct drm_gem_object *mtk_drm_gem_prime_import(struct drm_device *dev,
+                                               struct dma_buf *dma_buf)
+{
+       struct mtk_drm_private *private = dev->dev_private;
+
+       return drm_gem_prime_import_dev(dev, dma_buf, private->dma_dev);
+}
+
 static struct drm_driver mtk_drm_driver = {
        .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
                           DRIVER_ATOMIC,
@@ -331,7 +375,7 @@ static struct drm_driver mtk_drm_driver = {
        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
        .gem_prime_export = drm_gem_prime_export,
-       .gem_prime_import = drm_gem_prime_import,
+       .gem_prime_import = mtk_drm_gem_prime_import,
        .gem_prime_get_sg_table = mtk_gem_prime_get_sg_table,
        .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table,
        .gem_prime_mmap = mtk_drm_gem_mmap_buf,
@@ -524,12 +568,15 @@ static int mtk_drm_probe(struct platform_device *pdev)
                        comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
                        if (!comp) {
                                ret = -ENOMEM;
+                               of_node_put(node);
                                goto err_node;
                        }
 
                        ret = mtk_ddp_comp_init(dev, node, comp, comp_id, NULL);
-                       if (ret)
+                       if (ret) {
+                               of_node_put(node);
                                goto err_node;
+                       }
 
                        private->ddp_comp[comp_id] = comp;
                }
index 598ff3e..e03fea1 100644 (file)
@@ -51,6 +51,8 @@ struct mtk_drm_private {
        } commit;
 
        struct drm_atomic_state *suspend_state;
+
+       bool dma_parms_allocated;
 };
 
 extern struct platform_driver mtk_ddp_driver;
index 1267038..5c36c75 100644 (file)
@@ -771,16 +771,20 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
        struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
        int slots;
 
-       /* When restoring duplicated states, we need to make sure that the
-        * bw remains the same and avoid recalculating it, as the connector's
-        * bpc may have changed after the state was duplicated
-        */
-       if (!state->duplicated)
-               asyh->dp.pbn =
-                       drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock,
-                                            connector->display_info.bpc * 3);
+       if (crtc_state->mode_changed || crtc_state->connectors_changed) {
+               /*
+                * When restoring duplicated states, we need to make sure that
+                * the bw remains the same and avoid recalculating it, as the
+                * connector's bpc may have changed after the state was
+                * duplicated
+                */
+               if (!state->duplicated) {
+                       const int bpp = connector->display_info.bpc * 3;
+                       const int clock = crtc_state->adjusted_mode.clock;
+
+                       asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, bpp);
+               }
 
-       if (crtc_state->mode_changed) {
                slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr,
                                                      mstc->port,
                                                      asyh->dp.pbn);
index b4e7404..a11637b 100644 (file)
@@ -40,8 +40,7 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                u8 *ptr = msg->buf;
 
                while (remaining) {
-                       u8 cnt = (remaining > 16) ? 16 : remaining;
-                       u8 cmd;
+                       u8 cnt, retries, cmd;
 
                        if (msg->flags & I2C_M_RD)
                                cmd = 1;
@@ -51,10 +50,19 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        if (mcnt || remaining > 16)
                                cmd |= 4; /* MOT */
 
-                       ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, &cnt);
-                       if (ret < 0) {
-                               nvkm_i2c_aux_release(aux);
-                               return ret;
+                       for (retries = 0, cnt = 0;
+                            retries < 32 && !cnt;
+                            retries++) {
+                               cnt = min_t(u8, remaining, 16);
+                               ret = aux->func->xfer(aux, true, cmd,
+                                                     msg->addr, ptr, &cnt);
+                               if (ret < 0)
+                                       goto out;
+                       }
+                       if (!cnt) {
+                               AUX_TRACE(aux, "no data after 32 retries");
+                               ret = -EIO;
+                               goto out;
                        }
 
                        ptr += cnt;
@@ -64,8 +72,10 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                msg++;
        }
 
+       ret = num;
+out:
        nvkm_i2c_aux_release(aux);
-       return num;
+       return ret;
 }
 
 static u32
index 84a2f24..4695f1c 100644 (file)
@@ -190,6 +190,9 @@ MODULE_FIRMWARE("nvidia/gp102/nvdec/scrubber.bin");
 MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin");
 MODULE_FIRMWARE("nvidia/gp102/sec2/image.bin");
 MODULE_FIRMWARE("nvidia/gp102/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/gp102/sec2/desc-1.bin");
+MODULE_FIRMWARE("nvidia/gp102/sec2/image-1.bin");
+MODULE_FIRMWARE("nvidia/gp102/sec2/sig-1.bin");
 MODULE_FIRMWARE("nvidia/gp104/acr/bl.bin");
 MODULE_FIRMWARE("nvidia/gp104/acr/unload_bl.bin");
 MODULE_FIRMWARE("nvidia/gp104/acr/ucode_load.bin");
@@ -210,6 +213,9 @@ MODULE_FIRMWARE("nvidia/gp104/nvdec/scrubber.bin");
 MODULE_FIRMWARE("nvidia/gp104/sec2/desc.bin");
 MODULE_FIRMWARE("nvidia/gp104/sec2/image.bin");
 MODULE_FIRMWARE("nvidia/gp104/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/gp104/sec2/desc-1.bin");
+MODULE_FIRMWARE("nvidia/gp104/sec2/image-1.bin");
+MODULE_FIRMWARE("nvidia/gp104/sec2/sig-1.bin");
 MODULE_FIRMWARE("nvidia/gp106/acr/bl.bin");
 MODULE_FIRMWARE("nvidia/gp106/acr/unload_bl.bin");
 MODULE_FIRMWARE("nvidia/gp106/acr/ucode_load.bin");
@@ -230,6 +236,9 @@ MODULE_FIRMWARE("nvidia/gp106/nvdec/scrubber.bin");
 MODULE_FIRMWARE("nvidia/gp106/sec2/desc.bin");
 MODULE_FIRMWARE("nvidia/gp106/sec2/image.bin");
 MODULE_FIRMWARE("nvidia/gp106/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/gp106/sec2/desc-1.bin");
+MODULE_FIRMWARE("nvidia/gp106/sec2/image-1.bin");
+MODULE_FIRMWARE("nvidia/gp106/sec2/sig-1.bin");
 MODULE_FIRMWARE("nvidia/gp107/acr/bl.bin");
 MODULE_FIRMWARE("nvidia/gp107/acr/unload_bl.bin");
 MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin");
@@ -250,3 +259,6 @@ MODULE_FIRMWARE("nvidia/gp107/nvdec/scrubber.bin");
 MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin");
 MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin");
 MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
+MODULE_FIRMWARE("nvidia/gp107/sec2/desc-1.bin");
+MODULE_FIRMWARE("nvidia/gp107/sec2/image-1.bin");
+MODULE_FIRMWARE("nvidia/gp107/sec2/sig-1.bin");
index de0f882..14b41de 100644 (file)
@@ -4,6 +4,7 @@
  * Author: Archit Taneja <archit@ti.com>
  */
 
+#include <linux/bitops.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -20,7 +21,8 @@ int omapdss_device_init_output(struct omap_dss_device *out)
 {
        struct device_node *remote_node;
 
-       remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0);
+       remote_node = of_graph_get_remote_node(out->dev->of_node,
+                                              ffs(out->of_ports) - 1, 0);
        if (!remote_node) {
                dev_dbg(out->dev, "failed to find video sink\n");
                return 0;
index 288c59d..1bad0a2 100644 (file)
@@ -669,7 +669,7 @@ static int pdev_probe(struct platform_device *pdev)
        if (omapdss_is_initialized() == false)
                return -EPROBE_DEFER;
 
-       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (ret) {
                dev_err(&pdev->dev, "Failed to set the DMA mask\n");
                return ret;
index 92ac995..6e8145c 100644 (file)
@@ -222,7 +222,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo)
                size_t unmapped_page;
                size_t pgsize = get_pgsize(iova, len - unmapped_len);
 
-               unmapped_page = ops->unmap(ops, iova, pgsize);
+               unmapped_page = ops->unmap(ops, iova, pgsize, NULL);
                if (!unmapped_page)
                        break;
 
@@ -247,20 +247,28 @@ static void mmu_tlb_inv_context_s1(void *cookie)
        mmu_hw_do_operation(pfdev, 0, 0, ~0UL, AS_COMMAND_FLUSH_MEM);
 }
 
-static void mmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
-                                    size_t granule, bool leaf, void *cookie)
-{}
-
 static void mmu_tlb_sync_context(void *cookie)
 {
        //struct panfrost_device *pfdev = cookie;
        // TODO: Wait 1000 GPU cycles for HW_ISSUE_6367/T60X
 }
 
-static const struct iommu_gather_ops mmu_tlb_ops = {
+static void mmu_tlb_flush_walk(unsigned long iova, size_t size, size_t granule,
+                              void *cookie)
+{
+       mmu_tlb_sync_context(cookie);
+}
+
+static void mmu_tlb_flush_leaf(unsigned long iova, size_t size, size_t granule,
+                              void *cookie)
+{
+       mmu_tlb_sync_context(cookie);
+}
+
+static const struct iommu_flush_ops mmu_tlb_ops = {
        .tlb_flush_all  = mmu_tlb_inv_context_s1,
-       .tlb_add_flush  = mmu_tlb_inv_range_nosync,
-       .tlb_sync       = mmu_tlb_sync_context,
+       .tlb_flush_walk = mmu_tlb_flush_walk,
+       .tlb_flush_leaf = mmu_tlb_flush_leaf,
 };
 
 static const char *access_type_name(struct panfrost_device *pfdev,
index f33e349..952201c 100644 (file)
@@ -59,6 +59,11 @@ module_param_named(num_heads, qxl_num_crtc, int, 0400);
 static struct drm_driver qxl_driver;
 static struct pci_driver qxl_pci_driver;
 
+static bool is_vga(struct pci_dev *pdev)
+{
+       return pdev->class == PCI_CLASS_DISPLAY_VGA << 8;
+}
+
 static int
 qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -83,9 +88,17 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto disable_pci;
 
+       if (is_vga(pdev)) {
+               ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO);
+               if (ret) {
+                       DRM_ERROR("can't get legacy vga ioports\n");
+                       goto disable_pci;
+               }
+       }
+
        ret = qxl_device_init(qdev, &qxl_driver, pdev);
        if (ret)
-               goto disable_pci;
+               goto put_vga;
 
        ret = qxl_modeset_init(qdev);
        if (ret)
@@ -105,6 +118,9 @@ modeset_cleanup:
        qxl_modeset_fini(qdev);
 unload:
        qxl_device_fini(qdev);
+put_vga:
+       if (is_vga(pdev))
+               vga_put(pdev, VGA_RSRC_LEGACY_IO);
 disable_pci:
        pci_disable_device(pdev);
 free_dev:
@@ -122,6 +138,8 @@ qxl_pci_remove(struct pci_dev *pdev)
 
        qxl_modeset_fini(qdev);
        qxl_device_fini(qdev);
+       if (is_vga(pdev))
+               vga_put(pdev, VGA_RSRC_LEGACY_IO);
 
        dev->dev_private = NULL;
        kfree(qdev);
index 1c62578..082d02c 100644 (file)
@@ -673,10 +673,8 @@ static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds)
 
        /* Locate the companion LVDS encoder for dual-link operation, if any. */
        companion = of_parse_phandle(dev->of_node, "renesas,companion", 0);
-       if (!companion) {
-               dev_err(dev, "Companion LVDS encoder not found\n");
-               return -ENXIO;
-       }
+       if (!companion)
+               return 0;
 
        /*
         * Sanity check: the companion encoder must have the same compatible
index 35ddbec..671c90f 100644 (file)
@@ -95,7 +95,7 @@ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity)
        rmb(); /* for list_empty to work without lock */
 
        if (list_empty(&entity->list) ||
-           spsc_queue_peek(&entity->job_queue) == NULL)
+           spsc_queue_count(&entity->job_queue) == 0)
                return true;
 
        return false;
@@ -281,7 +281,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity)
        /* Consumption of existing IBs wasn't completed. Forcefully
         * remove them here.
         */
-       if (spsc_queue_peek(&entity->job_queue)) {
+       if (spsc_queue_count(&entity->job_queue)) {
                if (sched) {
                        /* Park the kernel for a moment to make sure it isn't processing
                         * our enity.
index b45824e..6d61a0e 100644 (file)
@@ -9,6 +9,13 @@
 
 #define cmdline_test(test)     selftest(test, test)
 
+cmdline_test(drm_cmdline_test_force_d_only)
+cmdline_test(drm_cmdline_test_force_D_only_dvi)
+cmdline_test(drm_cmdline_test_force_D_only_hdmi)
+cmdline_test(drm_cmdline_test_force_D_only_not_digital)
+cmdline_test(drm_cmdline_test_force_e_only)
+cmdline_test(drm_cmdline_test_margin_only)
+cmdline_test(drm_cmdline_test_interlace_only)
 cmdline_test(drm_cmdline_test_res)
 cmdline_test(drm_cmdline_test_res_missing_x)
 cmdline_test(drm_cmdline_test_res_missing_y)
index 14c96ed..013de9d 100644 (file)
 
 static const struct drm_connector no_connector = {};
 
+static int drm_cmdline_test_force_e_only(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(!drm_mode_parse_command_line_for_connector("e",
+                                                          &no_connector,
+                                                          &mode));
+       FAIL_ON(mode.specified);
+       FAIL_ON(mode.refresh_specified);
+       FAIL_ON(mode.bpp_specified);
+
+       FAIL_ON(mode.rb);
+       FAIL_ON(mode.cvt);
+       FAIL_ON(mode.interlace);
+       FAIL_ON(mode.margins);
+       FAIL_ON(mode.force != DRM_FORCE_ON);
+
+       return 0;
+}
+
+static int drm_cmdline_test_force_D_only_not_digital(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
+                                                          &no_connector,
+                                                          &mode));
+       FAIL_ON(mode.specified);
+       FAIL_ON(mode.refresh_specified);
+       FAIL_ON(mode.bpp_specified);
+
+       FAIL_ON(mode.rb);
+       FAIL_ON(mode.cvt);
+       FAIL_ON(mode.interlace);
+       FAIL_ON(mode.margins);
+       FAIL_ON(mode.force != DRM_FORCE_ON);
+
+       return 0;
+}
+
+static const struct drm_connector connector_hdmi = {
+       .connector_type = DRM_MODE_CONNECTOR_HDMIB,
+};
+
+static int drm_cmdline_test_force_D_only_hdmi(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
+                                                          &connector_hdmi,
+                                                          &mode));
+       FAIL_ON(mode.specified);
+       FAIL_ON(mode.refresh_specified);
+       FAIL_ON(mode.bpp_specified);
+
+       FAIL_ON(mode.rb);
+       FAIL_ON(mode.cvt);
+       FAIL_ON(mode.interlace);
+       FAIL_ON(mode.margins);
+       FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
+
+       return 0;
+}
+
+static const struct drm_connector connector_dvi = {
+       .connector_type = DRM_MODE_CONNECTOR_DVII,
+};
+
+static int drm_cmdline_test_force_D_only_dvi(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
+                                                          &connector_dvi,
+                                                          &mode));
+       FAIL_ON(mode.specified);
+       FAIL_ON(mode.refresh_specified);
+       FAIL_ON(mode.bpp_specified);
+
+       FAIL_ON(mode.rb);
+       FAIL_ON(mode.cvt);
+       FAIL_ON(mode.interlace);
+       FAIL_ON(mode.margins);
+       FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
+
+       return 0;
+}
+
+static int drm_cmdline_test_force_d_only(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(!drm_mode_parse_command_line_for_connector("d",
+                                                          &no_connector,
+                                                          &mode));
+       FAIL_ON(mode.specified);
+       FAIL_ON(mode.refresh_specified);
+       FAIL_ON(mode.bpp_specified);
+
+       FAIL_ON(mode.rb);
+       FAIL_ON(mode.cvt);
+       FAIL_ON(mode.interlace);
+       FAIL_ON(mode.margins);
+       FAIL_ON(mode.force != DRM_FORCE_OFF);
+
+       return 0;
+}
+
+static int drm_cmdline_test_margin_only(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(drm_mode_parse_command_line_for_connector("m",
+                                                         &no_connector,
+                                                         &mode));
+
+       return 0;
+}
+
+static int drm_cmdline_test_interlace_only(void *ignored)
+{
+       struct drm_cmdline_mode mode = { };
+
+       FAIL_ON(drm_mode_parse_command_line_for_connector("i",
+                                                         &no_connector,
+                                                         &mode));
+
+       return 0;
+}
+
 static int drm_cmdline_test_res(void *ignored)
 {
        struct drm_cmdline_mode mode = { };
index 64c43ee..df0cc8f 100644 (file)
@@ -314,6 +314,7 @@ static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
                /* R and B components are only 5 bits deep */
                val |= SUN4I_TCON0_FRM_CTL_MODE_R;
                val |= SUN4I_TCON0_FRM_CTL_MODE_B;
+               /* Fall through */
        case MEDIA_BUS_FMT_RGB666_1X18:
        case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
                /* Fall through: enable dithering */
index a1fc8b5..b889ad3 100644 (file)
@@ -993,6 +993,7 @@ static ssize_t sun6i_dsi_transfer(struct mipi_dsi_host *host,
                        ret = sun6i_dsi_dcs_read(dsi, msg);
                        break;
                }
+               /* Else, fall through */
 
        default:
                ret = -EINVAL;
index b2da313..09b5265 100644 (file)
@@ -204,6 +204,7 @@ int virtio_gpu_object_get_sg_table(struct virtio_gpu_device *qdev,
                .interruptible = false,
                .no_wait_gpu = false
        };
+       size_t max_segment;
 
        /* wtf swapping */
        if (bo->pages)
@@ -215,8 +216,13 @@ int virtio_gpu_object_get_sg_table(struct virtio_gpu_device *qdev,
        if (!bo->pages)
                goto out;
 
-       ret = sg_alloc_table_from_pages(bo->pages, pages, nr_pages, 0,
-                                       nr_pages << PAGE_SHIFT, GFP_KERNEL);
+       max_segment = virtio_max_dma_size(qdev->vdev);
+       max_segment &= PAGE_MASK;
+       if (max_segment > SCATTERLIST_MAX_SEGMENT)
+               max_segment = SCATTERLIST_MAX_SEGMENT;
+       ret = __sg_alloc_table_from_pages(bo->pages, pages, nr_pages, 0,
+                                         nr_pages << PAGE_SHIFT,
+                                         max_segment, GFP_KERNEL);
        if (ret)
                goto out;
        return 0;
index 59e9d05..0af048d 100644 (file)
@@ -353,7 +353,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
                                     !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
                if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
                        kfree(reply);
-
+                       reply = NULL;
                        if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
                                /* A checkpoint occurred. Retry. */
                                continue;
@@ -377,7 +377,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
 
                if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
                        kfree(reply);
-
+                       reply = NULL;
                        if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) {
                                /* A checkpoint occurred. Retry. */
                                continue;
@@ -389,10 +389,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
                break;
        }
 
-       if (retries == RETRIES) {
-               kfree(reply);
+       if (!reply)
                return -EINVAL;
-       }
 
        *msg_len = reply_len;
        *msg     = reply;
index 2310c96..db1b55d 100644 (file)
@@ -1153,8 +1153,6 @@ static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)
 
        INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
 
-       cp2112_gpio_direction_input(gc, d->hwirq);
-
        if (!dev->gpio_poll) {
                dev->gpio_poll = true;
                schedule_delayed_work(&dev->gpio_poll_worker, 0);
@@ -1204,6 +1202,12 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
                return PTR_ERR(dev->desc[pin]);
        }
 
+       ret = cp2112_gpio_direction_input(&dev->gc, pin);
+       if (ret < 0) {
+               dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
+               goto err_desc;
+       }
+
        ret = gpiochip_lock_as_irq(&dev->gc, pin);
        if (ret) {
                dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
index 21268c9..0179f7e 100644 (file)
@@ -3749,30 +3749,8 @@ static const struct hid_device_id hidpp_devices[] = {
 
        { L27MHZ_DEVICE(HID_ANY_ID) },
 
-       { /* Logitech G203/Prodigy Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC084) },
-       { /* Logitech G302 Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07F) },
-       { /* Logitech G303 Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC080) },
-       { /* Logitech G400 Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07E) },
        { /* Logitech G403 Wireless Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) },
-       { /* Logitech G403 Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC083) },
-       { /* Logitech G403 Hero Gaming Mouse over USB */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08F) },
-       { /* Logitech G502 Proteus Core Gaming Mouse */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07D) },
-       { /* Logitech G502 Proteus Spectrum Gaming Mouse over USB */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC332) },
-       { /* Logitech G502 Hero Gaming Mouse over USB */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08B) },
-       { /* Logitech G700 Gaming Mouse over USB */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC06B) },
-       { /* Logitech G700s Gaming Mouse over USB */
-         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07C) },
        { /* Logitech G703 Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) },
        { /* Logitech G703 Hero Gaming Mouse over USB */
index 1065692..5792a10 100644 (file)
@@ -24,6 +24,7 @@
 #define ICL_MOBILE_DEVICE_ID   0x34FC
 #define SPT_H_DEVICE_ID                0xA135
 #define CML_LP_DEVICE_ID       0x02FC
+#define EHL_Ax_DEVICE_ID       0x4BB3
 
 #define        REVISION_ID_CHT_A0      0x6
 #define        REVISION_ID_CHT_Ax_SI   0x0
index aa80b4d..279567b 100644 (file)
@@ -33,6 +33,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, EHL_Ax_DEVICE_ID)},
        {0, }
 };
 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
index 7a8ddc9..1713235 100644 (file)
@@ -846,6 +846,8 @@ static int wacom_intuos_general(struct wacom_wac *wacom)
                y >>= 1;
                distance >>= 1;
        }
+       if (features->type == INTUOSHT2)
+               distance = features->distance_max - distance;
        input_report_abs(input, ABS_X, x);
        input_report_abs(input, ABS_Y, y);
        input_report_abs(input, ABS_DISTANCE, distance);
@@ -1059,7 +1061,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
        input_report_key(input, BTN_BASE2, (data[11] & 0x02));
 
        if (data[12] & 0x80)
-               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1);
        else
                input_report_abs(input, ABS_WHEEL, 0);
 
@@ -1290,7 +1292,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
                }
                if (wacom->tool[0]) {
                        input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
-                       if (wacom->features.type == INTUOSP2_BT) {
+                       if (wacom->features.type == INTUOSP2_BT ||
+                           wacom->features.type == INTUOSP2S_BT) {
                                input_report_abs(pen_input, ABS_DISTANCE,
                                                 range ? frame[13] : wacom->features.distance_max);
                        } else {
index 5f9505a..23f358c 100644 (file)
@@ -26,7 +26,7 @@
 
 static unsigned long virt_to_hvpfn(void *addr)
 {
-       unsigned long paddr;
+       phys_addr_t paddr;
 
        if (is_vmalloc_addr(addr))
                paddr = page_to_phys(vmalloc_to_page(addr)) +
index 999f80a..e70783e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM hyperv
index 362e70e..fb16a62 100644 (file)
@@ -146,8 +146,6 @@ struct hv_context {
         */
        u64 guestid;
 
-       void *tsc_page;
-
        struct hv_per_cpu_context __percpu *cpu_context;
 
        /*
index 650dd71..2ca5668 100644 (file)
@@ -246,6 +246,16 @@ config SENSORS_ADT7475
          This driver can also be built as a module. If so, the module
          will be called adt7475.
 
+config SENSORS_AS370
+       tristate "Synaptics AS370 SoC hardware monitoring driver"
+       help
+         If you say yes here you get support for the PVT sensors of
+         the Synaptics AS370 SoC
+
+         This driver can also be built as a module. If so, the module
+         will be called as370-hwmon.
+
+
 config SENSORS_ASC7621
        tristate "Andigilog aSC7621"
        depends on I2C
@@ -1382,8 +1392,8 @@ config SENSORS_SHTC1
        tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
        depends on I2C
        help
-         If you say yes here you get support for the Sensiron SHTC1 and SHTW1
-         humidity and temperature sensors.
+         If you say yes here you get support for the Sensiron SHTC1, SHTW1,
+         and SHTC3 humidity and temperature sensors.
 
          This driver can also be built as a module. If so, the module
          will be called shtc1.
@@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818
          This driver can also be built as a module. If so, the module
          will be called adc128d818.
 
-config SENSORS_ADS1015
-       tristate "Texas Instruments ADS1015"
-       depends on I2C
-       help
-         If you say yes here you get support for Texas Instruments
-         ADS1015/ADS1115 12/16-bit 4-input ADC device.
-
-         This driver can also be built as a module. If so, the module
-         will be called ads1015.
-
 config SENSORS_ADS7828
        tristate "Texas Instruments ADS7828 and compatibles"
        depends on I2C
@@ -1834,17 +1834,12 @@ config SENSORS_W83795
          will be called w83795.
 
 config SENSORS_W83795_FANCTRL
-       bool "Include automatic fan control support (DANGEROUS)"
+       bool "Include automatic fan control support"
        depends on SENSORS_W83795
        help
          If you say yes here, support for automatic fan speed control
          will be included in the driver.
 
-         This part of the code wasn't carefully reviewed and tested yet,
-         so enabling this option is strongly discouraged on production
-         servers. Only developers and testers should enable it for the
-         time being.
-
          Please also note that this option will create sysfs attribute
          files which may change in the future, so you shouldn't rely
          on them being stable.
index 8db472e..c86ce4d 100644 (file)
@@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
 obj-$(CONFIG_SENSORS_ADM1029)  += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
-obj-$(CONFIG_SENSORS_ADS1015)  += ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
 obj-$(CONFIG_SENSORS_ADT7X10)  += adt7x10.o
@@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
 obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
 obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o
 obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
+obj-$(CONFIG_SENSORS_AS370)    += as370-hwmon.o
 obj-$(CONFIG_SENSORS_ASC7621)  += asc7621.o
 obj-$(CONFIG_SENSORS_ASPEED)   += aspeed-pwm-tacho.o
 obj-$(CONFIG_SENSORS_ATXP1)    += atxp1.o
index 6ba1a08..4cf2545 100644 (file)
@@ -681,8 +681,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
 
        if (resource->caps.flags & POWER_METER_CAN_CAP) {
                if (!can_cap_in_hardware()) {
-                       dev_err(&resource->acpi_dev->dev,
-                               "Ignoring unsafe software power cap!\n");
+                       dev_warn(&resource->acpi_dev->dev,
+                                "Ignoring unsafe software power cap!\n");
                        goto skip_unsafe_cap;
                }
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
deleted file mode 100644 (file)
index 3727a37..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
- * (C) Copyright 2010
- * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
- *
- * Based on the ads7828 driver by Steve Hardy.
- *
- * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-
-#include <linux/platform_data/ads1015.h>
-
-/* ADS1015 registers */
-enum {
-       ADS1015_CONVERSION = 0,
-       ADS1015_CONFIG = 1,
-};
-
-/* PGA fullscale voltages in mV */
-static const unsigned int fullscale_table[8] = {
-       6144, 4096, 2048, 1024, 512, 256, 256, 256 };
-
-/* Data rates in samples per second */
-static const unsigned int data_rate_table_1015[8] = {
-       128, 250, 490, 920, 1600, 2400, 3300, 3300
-};
-
-static const unsigned int data_rate_table_1115[8] = {
-       8, 16, 32, 64, 128, 250, 475, 860
-};
-
-#define ADS1015_DEFAULT_CHANNELS 0xff
-#define ADS1015_DEFAULT_PGA 2
-#define ADS1015_DEFAULT_DATA_RATE 4
-
-enum ads1015_chips {
-       ads1015,
-       ads1115,
-};
-
-struct ads1015_data {
-       struct device *hwmon_dev;
-       struct mutex update_lock; /* mutex protect updates */
-       struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
-       enum ads1015_chips id;
-};
-
-static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
-{
-       u16 config;
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       unsigned int pga = data->channel_data[channel].pga;
-       unsigned int data_rate = data->channel_data[channel].data_rate;
-       unsigned int conversion_time_ms;
-       const unsigned int * const rate_table = data->id == ads1115 ?
-               data_rate_table_1115 : data_rate_table_1015;
-       int res;
-
-       mutex_lock(&data->update_lock);
-
-       /* get channel parameters */
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
-       if (res < 0)
-               goto err_unlock;
-       config = res;
-       conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
-
-       /* setup and start single conversion */
-       config &= 0x001f;
-       config |= (1 << 15) | (1 << 8);
-       config |= (channel & 0x0007) << 12;
-       config |= (pga & 0x0007) << 9;
-       config |= (data_rate & 0x0007) << 5;
-
-       res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config);
-       if (res < 0)
-               goto err_unlock;
-
-       /* wait until conversion finished */
-       msleep(conversion_time_ms);
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
-       if (res < 0)
-               goto err_unlock;
-       config = res;
-       if (!(config & (1 << 15))) {
-               /* conversion not finished in time */
-               res = -EIO;
-               goto err_unlock;
-       }
-
-       res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION);
-
-err_unlock:
-       mutex_unlock(&data->update_lock);
-       return res;
-}
-
-static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
-                            s16 reg)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       unsigned int pga = data->channel_data[channel].pga;
-       int fullscale = fullscale_table[pga];
-       const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
-
-       return DIV_ROUND_CLOSEST(reg * fullscale, mask);
-}
-
-/* sysfs callback function */
-static ssize_t in_show(struct device *dev, struct device_attribute *da,
-                      char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct i2c_client *client = to_i2c_client(dev);
-       int res;
-       int index = attr->index;
-
-       res = ads1015_read_adc(client, index);
-       if (res < 0)
-               return res;
-
-       return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res));
-}
-
-static const struct sensor_device_attribute ads1015_in[] = {
-       SENSOR_ATTR_RO(in0_input, in, 0),
-       SENSOR_ATTR_RO(in1_input, in, 1),
-       SENSOR_ATTR_RO(in2_input, in, 2),
-       SENSOR_ATTR_RO(in3_input, in, 3),
-       SENSOR_ATTR_RO(in4_input, in, 4),
-       SENSOR_ATTR_RO(in5_input, in, 5),
-       SENSOR_ATTR_RO(in6_input, in, 6),
-       SENSOR_ATTR_RO(in7_input, in, 7),
-};
-
-/*
- * Driver interface
- */
-
-static int ads1015_remove(struct i2c_client *client)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       int k;
-
-       hwmon_device_unregister(data->hwmon_dev);
-       for (k = 0; k < ADS1015_CHANNELS; ++k)
-               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       return 0;
-}
-
-#ifdef CONFIG_OF
-static int ads1015_get_channels_config_of(struct i2c_client *client)
-{
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       struct device_node *node;
-
-       if (!client->dev.of_node
-           || !of_get_next_child(client->dev.of_node, NULL))
-               return -EINVAL;
-
-       for_each_child_of_node(client->dev.of_node, node) {
-               u32 pval;
-               unsigned int channel;
-               unsigned int pga = ADS1015_DEFAULT_PGA;
-               unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
-
-               if (of_property_read_u32(node, "reg", &pval)) {
-                       dev_err(&client->dev, "invalid reg on %pOF\n", node);
-                       continue;
-               }
-
-               channel = pval;
-               if (channel >= ADS1015_CHANNELS) {
-                       dev_err(&client->dev,
-                               "invalid channel index %d on %pOF\n",
-                               channel, node);
-                       continue;
-               }
-
-               if (!of_property_read_u32(node, "ti,gain", &pval)) {
-                       pga = pval;
-                       if (pga > 6) {
-                               dev_err(&client->dev, "invalid gain on %pOF\n",
-                                       node);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!of_property_read_u32(node, "ti,datarate", &pval)) {
-                       data_rate = pval;
-                       if (data_rate > 7) {
-                               dev_err(&client->dev,
-                                       "invalid data_rate on %pOF\n", node);
-                               return -EINVAL;
-                       }
-               }
-
-               data->channel_data[channel].enabled = true;
-               data->channel_data[channel].pga = pga;
-               data->channel_data[channel].data_rate = data_rate;
-       }
-
-       return 0;
-}
-#endif
-
-static void ads1015_get_channels_config(struct i2c_client *client)
-{
-       unsigned int k;
-       struct ads1015_data *data = i2c_get_clientdata(client);
-       struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
-
-       /* prefer platform data */
-       if (pdata) {
-               memcpy(data->channel_data, pdata->channel_data,
-                      sizeof(data->channel_data));
-               return;
-       }
-
-#ifdef CONFIG_OF
-       if (!ads1015_get_channels_config_of(client))
-               return;
-#endif
-
-       /* fallback on default configuration */
-       for (k = 0; k < ADS1015_CHANNELS; ++k) {
-               data->channel_data[k].enabled = true;
-               data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
-               data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
-       }
-}
-
-static int ads1015_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct ads1015_data *data;
-       int err;
-       unsigned int k;
-
-       data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
-                           GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       if (client->dev.of_node)
-               data->id = (enum ads1015_chips)
-                       of_device_get_match_data(&client->dev);
-       else
-               data->id = id->driver_data;
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       /* build sysfs attribute group */
-       ads1015_get_channels_config(client);
-       for (k = 0; k < ADS1015_CHANNELS; ++k) {
-               if (!data->channel_data[k].enabled)
-                       continue;
-               err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       for (k = 0; k < ADS1015_CHANNELS; ++k)
-               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       return err;
-}
-
-static const struct i2c_device_id ads1015_id[] = {
-       { "ads1015",  ads1015},
-       { "ads1115",  ads1115},
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ads1015_id);
-
-static const struct of_device_id __maybe_unused ads1015_of_match[] = {
-       {
-               .compatible = "ti,ads1015",
-               .data = (void *)ads1015
-       },
-       {
-               .compatible = "ti,ads1115",
-               .data = (void *)ads1115
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(of, ads1015_of_match);
-
-static struct i2c_driver ads1015_driver = {
-       .driver = {
-               .name = "ads1015",
-               .of_match_table = of_match_ptr(ads1015_of_match),
-       },
-       .probe = ads1015_probe,
-       .remove = ads1015_remove,
-       .id_table = ads1015_id,
-};
-
-module_i2c_driver(ads1015_driver);
-
-MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
-MODULE_DESCRIPTION("ADS1015 driver");
-MODULE_LICENSE("GPL");
index c3c6031..6c64d50 100644 (file)
@@ -187,7 +187,7 @@ static const struct of_device_id __maybe_unused adt7475_of_match[] = {
 MODULE_DEVICE_TABLE(of, adt7475_of_match);
 
 struct adt7475_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex lock;
 
        unsigned long measure_updated;
@@ -212,6 +212,7 @@ struct adt7475_data {
 
        u8 vid;
        u8 vrm;
+       const struct attribute_group *groups[9];
 };
 
 static struct i2c_driver adt7475_driver;
@@ -346,8 +347,8 @@ static ssize_t voltage_store(struct device *dev,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg;
        long val;
 
@@ -440,8 +441,8 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg = 0;
        u8 out;
        int temp;
@@ -542,8 +543,7 @@ static ssize_t temp_st_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
        long val;
 
        switch (sattr->index) {
@@ -570,8 +570,8 @@ static ssize_t temp_st_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg;
        int shift, idx;
        ulong val;
@@ -647,8 +647,8 @@ static ssize_t point2_show(struct device *dev, struct device_attribute *attr,
 static ssize_t point2_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
        int temp;
        long val;
@@ -710,8 +710,8 @@ static ssize_t tach_store(struct device *dev, struct device_attribute *attr,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val))
@@ -769,8 +769,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
 {
 
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned char reg = 0;
        long val;
 
@@ -818,8 +818,8 @@ static ssize_t stall_disable_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+
        u8 mask = BIT(5 + sattr->index);
 
        return sprintf(buf, "%d\n", !!(data->enh_acoustics[0] & mask));
@@ -830,8 +830,8 @@ static ssize_t stall_disable_store(struct device *dev,
                                   const char *buf, size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long val;
        u8 mask = BIT(5 + sattr->index);
 
@@ -914,8 +914,8 @@ static ssize_t pwmchan_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int r;
        long val;
 
@@ -938,8 +938,8 @@ static ssize_t pwmctrl_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int r;
        long val;
 
@@ -982,8 +982,8 @@ static ssize_t pwmfreq_store(struct device *dev,
                             size_t count)
 {
        struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int out;
        long val;
 
@@ -1022,8 +1022,8 @@ static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev,
                                        struct device_attribute *devattr,
                                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long val;
 
        if (kstrtol(buf, 10, &val))
@@ -1342,26 +1342,6 @@ static int adt7475_detect(struct i2c_client *client,
        return 0;
 }
 
-static void adt7475_remove_files(struct i2c_client *client,
-                                struct adt7475_data *data)
-{
-       sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
-       if (data->has_fan4)
-               sysfs_remove_group(&client->dev.kobj, &fan4_attr_group);
-       if (data->has_pwm2)
-               sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group);
-       if (data->has_voltage & (1 << 0))
-               sysfs_remove_group(&client->dev.kobj, &in0_attr_group);
-       if (data->has_voltage & (1 << 3))
-               sysfs_remove_group(&client->dev.kobj, &in3_attr_group);
-       if (data->has_voltage & (1 << 4))
-               sysfs_remove_group(&client->dev.kobj, &in4_attr_group);
-       if (data->has_voltage & (1 << 5))
-               sysfs_remove_group(&client->dev.kobj, &in5_attr_group);
-       if (data->has_vid)
-               sysfs_remove_group(&client->dev.kobj, &vid_attr_group);
-}
-
 static int adt7475_update_limits(struct i2c_client *client)
 {
        struct adt7475_data *data = i2c_get_clientdata(client);
@@ -1489,7 +1469,8 @@ static int adt7475_probe(struct i2c_client *client,
        };
 
        struct adt7475_data *data;
-       int i, ret = 0, revision;
+       struct device *hwmon_dev;
+       int i, ret = 0, revision, group_num = 0;
        u8 config2, config3;
 
        data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
@@ -1497,6 +1478,7 @@ static int adt7475_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mutex_init(&data->lock);
+       data->client = client;
        i2c_set_clientdata(client, data);
 
        if (client->dev.of_node)
@@ -1590,52 +1572,40 @@ static int adt7475_probe(struct i2c_client *client,
                break;
        }
 
-       ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
-       if (ret)
-               return ret;
+       data->groups[group_num++] = &adt7475_attr_group;
 
        /* Features that can be disabled individually */
        if (data->has_fan4) {
-               ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &fan4_attr_group;
        }
        if (data->has_pwm2) {
-               ret = sysfs_create_group(&client->dev.kobj, &pwm2_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &pwm2_attr_group;
        }
        if (data->has_voltage & (1 << 0)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in0_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in0_attr_group;
        }
        if (data->has_voltage & (1 << 3)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in3_attr_group;
        }
        if (data->has_voltage & (1 << 4)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in4_attr_group;
        }
        if (data->has_voltage & (1 << 5)) {
-               ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num++] = &in5_attr_group;
        }
        if (data->has_vid) {
                data->vrm = vid_which_vrm();
-               ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group);
-               if (ret)
-                       goto eremove;
+               data->groups[group_num] = &vid_attr_group;
        }
 
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               ret = PTR_ERR(data->hwmon_dev);
-               goto eremove;
+       /* register device with all the acquired attributes */
+       hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+                                                          client->name, data,
+                                                          data->groups);
+
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
+               return ret;
        }
 
        dev_info(&client->dev, "%s device, revision %d\n",
@@ -1657,21 +1627,7 @@ static int adt7475_probe(struct i2c_client *client,
        /* Limits and settings, should never change update more than once */
        ret = adt7475_update_limits(client);
        if (ret)
-               goto eremove;
-
-       return 0;
-
-eremove:
-       adt7475_remove_files(client, data);
-       return ret;
-}
-
-static int adt7475_remove(struct i2c_client *client)
-{
-       struct adt7475_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       adt7475_remove_files(client, data);
+               return ret;
 
        return 0;
 }
@@ -1683,7 +1639,6 @@ static struct i2c_driver adt7475_driver = {
                .of_match_table = of_match_ptr(adt7475_of_match),
        },
        .probe          = adt7475_probe,
-       .remove         = adt7475_remove,
        .id_table       = adt7475_id,
        .detect         = adt7475_detect,
        .address_list   = normal_i2c,
@@ -1757,8 +1712,8 @@ static void adt7475_read_pwm(struct i2c_client *client, int index)
 
 static int adt7475_update_measure(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        u16 ext;
        int i;
        int ret;
@@ -1854,8 +1809,7 @@ static int adt7475_update_measure(struct device *dev)
 
 static struct adt7475_data *adt7475_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7475_data *data = i2c_get_clientdata(client);
+       struct adt7475_data *data = dev_get_drvdata(dev);
        int ret;
 
        mutex_lock(&data->lock);
diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c
new file mode 100644 (file)
index 0000000..464244b
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Synaptics AS370 SoC Hardware Monitoring Driver
+ *
+ * Copyright (C) 2018 Synaptics Incorporated
+ * Author: Jisheng Zhang <jszhang@kernel.org>
+ */
+
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#define CTRL           0x0
+#define  PD            BIT(0)
+#define  EN            BIT(1)
+#define  T_SEL         BIT(2)
+#define  V_SEL         BIT(3)
+#define  NMOS_SEL      BIT(8)
+#define  PMOS_SEL      BIT(9)
+#define STS            0x4
+#define  BN_MASK       GENMASK(11, 0)
+#define  EOC           BIT(12)
+
+struct as370_hwmon {
+       void __iomem *base;
+};
+
+static void init_pvt(struct as370_hwmon *hwmon)
+{
+       u32 val;
+       void __iomem *addr = hwmon->base + CTRL;
+
+       val = PD;
+       writel_relaxed(val, addr);
+       val |= T_SEL;
+       writel_relaxed(val, addr);
+       val |= EN;
+       writel_relaxed(val, addr);
+       val &= ~PD;
+       writel_relaxed(val, addr);
+}
+
+static int as370_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+                           u32 attr, int channel, long *temp)
+{
+       int val;
+       struct as370_hwmon *hwmon = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_temp_input:
+               val = readl_relaxed(hwmon->base + STS) & BN_MASK;
+               *temp = DIV_ROUND_CLOSEST(val * 251802, 4096) - 85525;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static umode_t
+as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
+                      u32 attr, int channel)
+{
+       if (type != hwmon_temp)
+               return 0;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static const u32 as370_hwmon_temp_config[] = {
+       HWMON_T_INPUT,
+       0
+};
+
+static const struct hwmon_channel_info as370_hwmon_temp = {
+       .type = hwmon_temp,
+       .config = as370_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *as370_hwmon_info[] = {
+       &as370_hwmon_temp,
+       NULL
+};
+
+static const struct hwmon_ops as370_hwmon_ops = {
+       .is_visible = as370_hwmon_is_visible,
+       .read = as370_hwmon_read,
+};
+
+static const struct hwmon_chip_info as370_chip_info = {
+       .ops = &as370_hwmon_ops,
+       .info = as370_hwmon_info,
+};
+
+static int as370_hwmon_probe(struct platform_device *pdev)
+{
+       struct device *hwmon_dev;
+       struct as370_hwmon *hwmon;
+       struct device *dev = &pdev->dev;
+
+       hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+       if (!hwmon)
+               return -ENOMEM;
+
+       hwmon->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(hwmon->base))
+               return PTR_ERR(hwmon->base);
+
+       init_pvt(hwmon);
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev,
+                                                        "as370",
+                                                        hwmon,
+                                                        &as370_chip_info,
+                                                        NULL);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id as370_hwmon_match[] = {
+       { .compatible = "syna,as370-hwmon" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, as370_hwmon_match);
+
+static struct platform_driver as370_hwmon_driver = {
+       .probe = as370_hwmon_probe,
+       .driver = {
+               .name = "as370-hwmon",
+               .of_match_table = as370_hwmon_match,
+       },
+};
+module_platform_driver(as370_hwmon_driver);
+
+MODULE_AUTHOR("Jisheng Zhang<jszhang@kernel.org>");
+MODULE_DESCRIPTION("Synaptics AS370 SoC hardware monitor");
+MODULE_LICENSE("GPL v2");
index c9fa84b..4c609e2 100644 (file)
@@ -706,21 +706,21 @@ static int asb100_detect_subclients(struct i2c_client *client)
                goto ERROR_SC_2;
        }
 
-       data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
-       if (!data->lm75[0]) {
+       data->lm75[0] = i2c_new_dummy_device(adapter, sc_addr[0]);
+       if (IS_ERR(data->lm75[0])) {
                dev_err(&client->dev,
                        "subclient %d registration at address 0x%x failed.\n",
                        1, sc_addr[0]);
-               err = -ENOMEM;
+               err = PTR_ERR(data->lm75[0]);
                goto ERROR_SC_2;
        }
 
-       data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
-       if (!data->lm75[1]) {
+       data->lm75[1] = i2c_new_dummy_device(adapter, sc_addr[1]);
+       if (IS_ERR(data->lm75[1])) {
                dev_err(&client->dev,
                        "subclient %d registration at address 0x%x failed.\n",
                        2, sc_addr[1]);
-               err = -ENOMEM;
+               err = PTR_ERR(data->lm75[1]);
                goto ERROR_SC_3;
        }
 
index fe6618e..d855c78 100644 (file)
@@ -736,7 +736,7 @@ static int __init coretemp_init(void)
 
        err = platform_driver_register(&coretemp_driver);
        if (err)
-               return err;
+               goto outzone;
 
        err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
                                coretemp_cpu_online, coretemp_cpu_offline);
@@ -747,6 +747,7 @@ static int __init coretemp_init(void)
 
 outdrv:
        platform_driver_unregister(&coretemp_driver);
+outzone:
        kfree(zone_devices);
        return err;
 }
index f1c2d5f..b85a125 100644 (file)
@@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
        int ret;
        struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
        struct iio_hwmon_state *state = dev_get_drvdata(dev);
+       struct iio_channel *chan = &state->channels[sattr->index];
+       enum iio_chan_type type;
+
+       ret = iio_read_channel_processed(chan, &result);
+       if (ret < 0)
+               return ret;
 
-       ret = iio_read_channel_processed(&state->channels[sattr->index],
-                                       &result);
+       ret = iio_get_channel_type(chan, &type);
        if (ret < 0)
                return ret;
 
+       if (type == IIO_POWER)
+               result *= 1000; /* mili-Watts to micro-Watts conversion */
+
        return sprintf(buf, "%d\n", result);
 }
 
@@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
        struct iio_hwmon_state *st;
        struct sensor_device_attribute *a;
        int ret, i;
-       int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
+       int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1;
        enum iio_chan_type type;
        struct iio_channel *channels;
        struct device *hwmon_dev;
@@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
                        n = curr_i++;
                        prefix = "curr";
                        break;
+               case IIO_POWER:
+                       n = power_i++;
+                       prefix = "power";
+                       break;
                case IIO_HUMIDITYRELATIVE:
                        n = humidity_i++;
                        prefix = "humidity";
index c77e892..5c1dddd 100644 (file)
@@ -349,6 +349,7 @@ static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
        { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        {}
 };
index 4994c90..f73bd4e 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/pci.h>
 #include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/processor.h>
 #define SEL_CORE       0x04
 
 struct k8temp_data {
-       struct device *hwmon_dev;
        struct mutex update_lock;
-       const char *name;
-       char valid;             /* zero until following fields are valid */
-       unsigned long last_updated;     /* in jiffies */
 
        /* registers values */
        u8 sensorsp;            /* sensor presence bits - SEL_CORE, SEL_PLACE */
-       u32 temp[2][2];         /* core, place */
        u8 swap_core_select;    /* meaning of SEL_CORE is inverted */
        u32 temp_offset;
 };
 
-static struct k8temp_data *k8temp_update_device(struct device *dev)
-{
-       struct k8temp_data *data = dev_get_drvdata(dev);
-       struct pci_dev *pdev = to_pci_dev(dev);
-       u8 tmp;
-
-       mutex_lock(&data->update_lock);
-
-       if (!data->valid
-           || time_after(jiffies, data->last_updated + HZ)) {
-               pci_read_config_byte(pdev, REG_TEMP, &tmp);
-               tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
-               pci_write_config_byte(pdev, REG_TEMP, tmp);
-               pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
-
-               if (data->sensorsp & SEL_PLACE) {
-                       tmp |= SEL_PLACE;       /* Select sensor 1, core0 */
-                       pci_write_config_byte(pdev, REG_TEMP, tmp);
-                       pci_read_config_dword(pdev, REG_TEMP,
-                                             &data->temp[0][1]);
-               }
-
-               if (data->sensorsp & SEL_CORE) {
-                       tmp &= ~SEL_PLACE;      /* Select sensor 0, core1 */
-                       tmp |= SEL_CORE;
-                       pci_write_config_byte(pdev, REG_TEMP, tmp);
-                       pci_read_config_dword(pdev, REG_TEMP,
-                                             &data->temp[1][0]);
-
-                       if (data->sensorsp & SEL_PLACE) {
-                               tmp |= SEL_PLACE; /* Select sensor 1, core1 */
-                               pci_write_config_byte(pdev, REG_TEMP, tmp);
-                               pci_read_config_dword(pdev, REG_TEMP,
-                                                     &data->temp[1][1]);
-                       }
-               }
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-       return data;
-}
-
-/*
- * Sysfs stuff
- */
-
-static ssize_t name_show(struct device *dev, struct device_attribute
-                        *devattr, char *buf)
-{
-       struct k8temp_data *data = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%s\n", data->name);
-}
-
-
-static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
-                        char *buf)
-{
-       struct sensor_device_attribute_2 *attr =
-           to_sensor_dev_attr_2(devattr);
-       int core = attr->nr;
-       int place = attr->index;
-       int temp;
-       struct k8temp_data *data = k8temp_update_device(dev);
-
-       if (data->swap_core_select && (data->sensorsp & SEL_CORE))
-               core = core ? 0 : 1;
-
-       temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
-
-       return sprintf(buf, "%d\n", temp);
-}
-
-/* core, place */
-
-static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0, 0);
-static SENSOR_DEVICE_ATTR_2_RO(temp2_input, temp, 0, 1);
-static SENSOR_DEVICE_ATTR_2_RO(temp3_input, temp, 1, 0);
-static SENSOR_DEVICE_ATTR_2_RO(temp4_input, temp, 1, 1);
-static DEVICE_ATTR_RO(name);
-
 static const struct pci_device_id k8temp_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { 0 },
 };
-
 MODULE_DEVICE_TABLE(pci, k8temp_ids);
 
 static int is_rev_g_desktop(u8 model)
@@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model)
        return 1;
 }
 
+static umode_t
+k8temp_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+                 u32 attr, int channel)
+{
+       const struct k8temp_data *data = drvdata;
+
+       if ((channel & 1) && !(data->sensorsp & SEL_PLACE))
+               return 0;
+
+       if ((channel & 2) && !(data->sensorsp & SEL_CORE))
+               return 0;
+
+       return 0444;
+}
+
+static int
+k8temp_read(struct device *dev, enum hwmon_sensor_types type,
+           u32 attr, int channel, long *val)
+{
+       struct k8temp_data *data = dev_get_drvdata(dev);
+       struct pci_dev *pdev = to_pci_dev(dev->parent);
+       int core, place;
+       u32 temp;
+       u8 tmp;
+
+       core = (channel >> 1) & 1;
+       place = channel & 1;
+
+       core ^= data->swap_core_select;
+
+       mutex_lock(&data->update_lock);
+       pci_read_config_byte(pdev, REG_TEMP, &tmp);
+       tmp &= ~(SEL_PLACE | SEL_CORE);
+       if (core)
+               tmp |= SEL_CORE;
+       if (place)
+               tmp |= SEL_PLACE;
+       pci_write_config_byte(pdev, REG_TEMP, tmp);
+       pci_read_config_dword(pdev, REG_TEMP, &temp);
+       mutex_unlock(&data->update_lock);
+
+       *val = TEMP_FROM_REG(temp) + data->temp_offset;
+
+       return 0;
+}
+
+static const struct hwmon_ops k8temp_ops = {
+       .is_visible = k8temp_is_visible,
+       .read = k8temp_read,
+};
+
+static const struct hwmon_channel_info *k8temp_info[] = {
+       HWMON_CHANNEL_INFO(temp,
+               HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT),
+       NULL
+};
+
+static const struct hwmon_chip_info k8temp_chip_info = {
+       .ops = &k8temp_ops,
+       .info = k8temp_info,
+};
+
 static int k8temp_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *id)
 {
-       int err;
        u8 scfg;
        u32 temp;
        u8 model, stepping;
        struct k8temp_data *data;
+       struct device *hwmon_dev;
 
        data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
        if (!data)
@@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev,
                        data->sensorsp &= ~SEL_CORE;
        }
 
-       data->name = "k8temp";
        mutex_init(&data->update_lock);
-       pci_set_drvdata(pdev, data);
-
-       /* Register sysfs hooks */
-       err = device_create_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       if (err)
-               goto exit_remove;
-
-       /* sensor can be changed and reports something */
-       if (data->sensorsp & SEL_PLACE) {
-               err = device_create_file(&pdev->dev,
-                                  &sensor_dev_attr_temp2_input.dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       /* core can be changed and reports something */
-       if (data->sensorsp & SEL_CORE) {
-               err = device_create_file(&pdev->dev,
-                                  &sensor_dev_attr_temp3_input.dev_attr);
-               if (err)
-                       goto exit_remove;
-               if (data->sensorsp & SEL_PLACE) {
-                       err = device_create_file(&pdev->dev,
-                                          &sensor_dev_attr_temp4_input.
-                                          dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-       }
-
-       err = device_create_file(&pdev->dev, &dev_attr_name);
-       if (err)
-               goto exit_remove;
 
-       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
+                                                        "k8temp",
+                                                        data,
+                                                        &k8temp_chip_info,
+                                                        NULL);
 
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp2_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp3_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp4_input.dev_attr);
-       device_remove_file(&pdev->dev, &dev_attr_name);
-       return err;
-}
-
-static void k8temp_remove(struct pci_dev *pdev)
-{
-       struct k8temp_data *data = pci_get_drvdata(pdev);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp1_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp2_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp3_input.dev_attr);
-       device_remove_file(&pdev->dev,
-                          &sensor_dev_attr_temp4_input.dev_attr);
-       device_remove_file(&pdev->dev, &dev_attr_name);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static struct pci_driver k8temp_driver = {
        .name = "k8temp",
        .id_table = k8temp_ids,
        .probe = k8temp_probe,
-       .remove = k8temp_remove,
 };
 
 module_pci_driver(k8temp_driver);
index ce5ec40..5e63922 100644 (file)
@@ -16,9 +16,9 @@
 #include <linux/of_device.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
+#include <linux/util_macros.h>
 #include "lm75.h"
 
-
 /*
  * This driver handles the LM75 and compatible digital temperature sensors.
  */
@@ -36,6 +36,7 @@ enum lm75_type {              /* keep sorted in alphabetical order */
        max6626,
        max31725,
        mcp980x,
+       pct2075,
        stds75,
        stlm75,
        tcn75,
@@ -50,6 +51,41 @@ enum lm75_type {             /* keep sorted in alphabetical order */
        tmp75c,
 };
 
+/**
+ * struct lm75_params - lm75 configuration parameters.
+ * @set_mask:          Bits to set in configuration register when configuring
+ *                     the chip.
+ * @clr_mask:          Bits to clear in configuration register when configuring
+ *                     the chip.
+ * @default_resolution:        Default number of bits to represent the temperature
+ *                     value.
+ * @resolution_limits: Limit register resolution. Optional. Should be set if
+ *                     the resolution of limit registers does not match the
+ *                     resolution of the temperature register.
+ * @resolutions:       List of resolutions associated with sample times.
+ *                     Optional. Should be set if num_sample_times is larger
+ *                     than 1, and if the resolution changes with sample times.
+ *                     If set, number of entries must match num_sample_times.
+ * @default_sample_time:Sample time to be set by default.
+ * @num_sample_times:  Number of possible sample times to be set. Optional.
+ *                     Should be set if the number of sample times is larger
+ *                     than one.
+ * @sample_times:      All the possible sample times to be set. Mandatory if
+ *                     num_sample_times is larger than 1. If set, number of
+ *                     entries must match num_sample_times.
+ */
+
+struct lm75_params {
+       u8                      set_mask;
+       u8                      clr_mask;
+       u8                      default_resolution;
+       u8                      resolution_limits;
+       const u8                *resolutions;
+       unsigned int            default_sample_time;
+       u8                      num_sample_times;
+       const unsigned int      *sample_times;
+};
+
 /* Addresses scanned */
 static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
                                        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
@@ -59,24 +95,231 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
 #define LM75_REG_CONF          0x01
 #define LM75_REG_HYST          0x02
 #define LM75_REG_MAX           0x03
+#define PCT2075_REG_IDLE       0x04
 
 /* Each client has this additional data */
 struct lm75_data {
-       struct i2c_client       *client;
-       struct regmap           *regmap;
-       u8                      orig_conf;
-       u8                      resolution;     /* In bits, between 9 and 16 */
-       u8                      resolution_limits;
-       unsigned int            sample_time;    /* In ms */
+       struct i2c_client               *client;
+       struct regmap                   *regmap;
+       u8                              orig_conf;
+       u8                              current_conf;
+       u8                              resolution;     /* In bits, 9 to 16 */
+       unsigned int                    sample_time;    /* In ms */
+       enum lm75_type                  kind;
+       const struct lm75_params        *params;
 };
 
 /*-----------------------------------------------------------------------*/
 
+static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
+
+#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
+
+/* The structure below stores the configuration values of the supported devices.
+ * In case of being supported multiple configurations, the default one must
+ * always be the first element of the array
+ */
+static const struct lm75_params device_params[] = {
+       [adt75] = {
+               .clr_mask = 1 << 5,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [ds1775] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 500,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 125, 250, 500, 1000 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [ds75] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 600,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 150, 300, 600, 1200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [stds75] = {
+               .clr_mask = 3 << 5,
+               .set_mask = 2 << 5,     /* 11-bit mode */
+               .default_resolution = 11,
+               .default_sample_time = 600,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 150, 300, 600, 1200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [stlm75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 6,
+       },
+       [ds7505] = {
+               .set_mask = 3 << 5,     /* 12-bit mode*/
+               .default_resolution = 12,
+               .default_sample_time = 200,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 25, 50, 100, 200 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [g751] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75a] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [lm75b] = {
+               .default_resolution = 11,
+               .default_sample_time = MSEC_PER_SEC / 10,
+       },
+       [max6625] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 7,
+       },
+       [max6626] = {
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 7,
+               .resolution_limits = 9,
+       },
+       [max31725] = {
+               .default_resolution = 16,
+               .default_sample_time = MSEC_PER_SEC / 20,
+       },
+       [tcn75] = {
+               .default_resolution = 9,
+               .default_sample_time = MSEC_PER_SEC / 18,
+       },
+       [pct2075] = {
+               .default_resolution = 11,
+               .default_sample_time = MSEC_PER_SEC / 10,
+               .num_sample_times = 31,
+               .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600,
+               700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700,
+               1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
+               2800, 2900, 3000, 3100 },
+       },
+       [mcp980x] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .resolution_limits = 9,
+               .default_sample_time = 240,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 30, 60, 120, 240 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp100] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = 320,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 40, 80, 160, 320 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp101] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode */
+               .default_resolution = 12,
+               .default_sample_time = 320,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 40, 80, 160, 320 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp105] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp112] = {
+               .set_mask = 3 << 5,     /* 8 samples / second */
+               .clr_mask = 1 << 7,     /* no one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 125,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 125, 250, 1000, 4000 },
+       },
+       [tmp175] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp275] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp75] = {
+               .set_mask = 3 << 5,     /* 12-bit mode */
+               .clr_mask = 1 << 7,     /* not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = 220,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+               .resolutions = (u8 []) {9, 10, 11, 12 },
+       },
+       [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */
+               .clr_mask = 1 << 7 | 3 << 5,
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 37,
+               .sample_times = (unsigned int []){ MSEC_PER_SEC / 37,
+                       MSEC_PER_SEC / 18,
+                       MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 },
+               .num_sample_times = 4,
+       },
+       [tmp75c] = {
+               .clr_mask = 1 << 5,     /*not one-shot mode*/
+               .default_resolution = 12,
+               .default_sample_time = MSEC_PER_SEC / 12,
+       }
+};
+
 static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
 {
        return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
 }
 
+static int lm75_write_config(struct lm75_data *data, u8 set_mask,
+                            u8 clr_mask)
+{
+       u8 value;
+
+       clr_mask |= LM75_SHUTDOWN;
+       value = data->current_conf & ~clr_mask;
+       value |= set_mask;
+
+       if (data->current_conf != value) {
+               s32 err;
+
+               err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF,
+                                               value);
+               if (err)
+                       return err;
+               data->current_conf = value;
+       }
+       return 0;
+}
+
 static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
                     u32 attr, int channel, long *val)
 {
@@ -120,16 +363,12 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
        return 0;
 }
 
-static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
-                     u32 attr, int channel, long temp)
+static int lm75_write_temp(struct device *dev, u32 attr, long temp)
 {
        struct lm75_data *data = dev_get_drvdata(dev);
        u8 resolution;
        int reg;
 
-       if (type != hwmon_temp)
-               return -EINVAL;
-
        switch (attr) {
        case hwmon_temp_max:
                reg = LM75_REG_MAX;
@@ -145,8 +384,8 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
         * Resolution of limit registers is assumed to be the same as the
         * temperature input register resolution unless given explicitly.
         */
-       if (data->resolution_limits)
-               resolution = data->resolution_limits;
+       if (data->params->resolution_limits)
+               resolution = data->params->resolution_limits;
        else
                resolution = data->resolution;
 
@@ -154,16 +393,88 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
        temp = DIV_ROUND_CLOSEST(temp  << (resolution - 8),
                                 1000) << (16 - resolution);
 
-       return regmap_write(data->regmap, reg, temp);
+       return regmap_write(data->regmap, reg, (u16)temp);
+}
+
+static int lm75_update_interval(struct device *dev, long val)
+{
+       struct lm75_data *data = dev_get_drvdata(dev);
+       unsigned int reg;
+       u8 index;
+       s32 err;
+
+       index = find_closest(val, data->params->sample_times,
+                            (int)data->params->num_sample_times);
+
+       switch (data->kind) {
+       default:
+               err = lm75_write_config(data, lm75_sample_set_masks[index],
+                                       LM75_SAMPLE_CLEAR_MASK);
+               if (err)
+                       return err;
+
+               data->sample_time = data->params->sample_times[index];
+               if (data->params->resolutions)
+                       data->resolution = data->params->resolutions[index];
+               break;
+       case tmp112:
+               err = regmap_read(data->regmap, LM75_REG_CONF, &reg);
+               if (err < 0)
+                       return err;
+               reg &= ~0x00c0;
+               reg |= (3 - index) << 6;
+               err = regmap_write(data->regmap, LM75_REG_CONF, reg);
+               if (err < 0)
+                       return err;
+               data->sample_time = data->params->sample_times[index];
+               break;
+       case pct2075:
+               err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE,
+                                               index + 1);
+               if (err)
+                       return err;
+               data->sample_time = data->params->sample_times[index];
+               break;
+       }
+       return 0;
+}
+
+static int lm75_write_chip(struct device *dev, u32 attr, long val)
+{
+       switch (attr) {
+       case hwmon_chip_update_interval:
+               return lm75_update_interval(dev, val);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
+                     u32 attr, int channel, long val)
+{
+       switch (type) {
+       case hwmon_chip:
+               return lm75_write_chip(dev, attr, val);
+       case hwmon_temp:
+               return lm75_write_temp(dev, attr, val);
+       default:
+               return -EINVAL;
+       }
+       return 0;
 }
 
 static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
                               u32 attr, int channel)
 {
+       const struct lm75_data *config_data = data;
+
        switch (type) {
        case hwmon_chip:
                switch (attr) {
                case hwmon_chip_update_interval:
+                       if (config_data->params->num_sample_times > 1)
+                               return 0644;
                        return 0444;
                }
                break;
@@ -208,13 +519,13 @@ static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg)
 
 static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg)
 {
-       return reg == LM75_REG_TEMP;
+       return reg == LM75_REG_TEMP || reg == LM75_REG_CONF;
 }
 
 static const struct regmap_config lm75_regmap_config = {
        .reg_bits = 8,
        .val_bits = 16,
-       .max_register = LM75_REG_MAX,
+       .max_register = PCT2075_REG_IDLE,
        .writeable_reg = lm75_is_writeable_reg,
        .volatile_reg = lm75_is_volatile_reg,
        .val_format_endian = REGMAP_ENDIAN_BIG,
@@ -238,8 +549,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        struct device *hwmon_dev;
        struct lm75_data *data;
        int status, err;
-       u8 set_mask, clr_mask;
-       int new;
        enum lm75_type kind;
 
        if (client->dev.of_node)
@@ -256,6 +565,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -ENOMEM;
 
        data->client = client;
+       data->kind = kind;
 
        data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config);
        if (IS_ERR(data->regmap))
@@ -264,113 +574,30 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
         * Then tweak to be more precise when appropriate.
         */
-       set_mask = 0;
-       clr_mask = LM75_SHUTDOWN;               /* continuous conversions */
-
-       switch (kind) {
-       case adt75:
-               clr_mask |= 1 << 5;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case ds1775:
-       case ds75:
-       case stds75:
-               clr_mask |= 3 << 5;
-               set_mask |= 2 << 5;             /* 11-bit mode */
-               data->resolution = 11;
-               data->sample_time = MSEC_PER_SEC;
-               break;
-       case stlm75:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 5;
-               break;
-       case ds7505:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case g751:
-       case lm75:
-       case lm75a:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 2;
-               break;
-       case lm75b:
-               data->resolution = 11;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max6625:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max6626:
-               data->resolution = 12;
-               data->resolution_limits = 9;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case max31725:
-               data->resolution = 16;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case tcn75:
-               data->resolution = 9;
-               data->sample_time = MSEC_PER_SEC / 8;
-               break;
-       case mcp980x:
-               data->resolution_limits = 9;
-               /* fall through */
-       case tmp100:
-       case tmp101:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC;
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               break;
-       case tmp112:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       case tmp105:
-       case tmp175:
-       case tmp275:
-       case tmp75:
-               set_mask |= 3 << 5;             /* 12-bit mode */
-               clr_mask |= 1 << 7;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 2;
-               break;
-       case tmp75b:  /* not one-shot mode, Conversion rate 37Hz */
-               clr_mask |= 1 << 7 | 0x3 << 5;
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 37;
-               break;
-       case tmp75c:
-               clr_mask |= 1 << 5;             /* not one-shot mode */
-               data->resolution = 12;
-               data->sample_time = MSEC_PER_SEC / 4;
-               break;
-       }
 
-       /* configure as specified */
+       data->params = &device_params[data->kind];
+
+       /* Save default sample time and resolution*/
+       data->sample_time = data->params->default_sample_time;
+       data->resolution = data->params->default_resolution;
+
+       /* Cache original configuration */
        status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
        if (status < 0) {
                dev_dbg(dev, "Can't read config? %d\n", status);
                return status;
        }
        data->orig_conf = status;
-       new = status & ~clr_mask;
-       new |= set_mask;
-       if (status != new)
-               i2c_smbus_write_byte_data(client, LM75_REG_CONF, new);
+       data->current_conf = status;
 
-       err = devm_add_action_or_reset(dev, lm75_remove, data);
+       err = lm75_write_config(data, data->params->set_mask,
+                               data->params->clr_mask);
        if (err)
                return err;
 
-       dev_dbg(dev, "Config %02x\n", new);
+       err = devm_add_action_or_reset(dev, lm75_remove, data);
+       if (err)
+               return err;
 
        hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
                                                         data, &lm75_chip_info,
@@ -397,6 +624,7 @@ static const struct i2c_device_id lm75_ids[] = {
        { "max31725", max31725, },
        { "max31726", max31725, },
        { "mcp980x", mcp980x, },
+       { "pct2075", pct2075, },
        { "stds75", stds75, },
        { "stlm75", stlm75, },
        { "tcn75", tcn75, },
@@ -466,6 +694,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
                .compatible = "maxim,mcp980x",
                .data = (void *)mcp980x
        },
+       {
+               .compatible = "nxp,pct2075",
+               .data = (void *)pct2075
+       },
        {
                .compatible = "st,stds75",
                .data = (void *)stds75
index f9431ad..53ff505 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/property.h>
 
 #define LTC2990_STATUS 0x00
 #define LTC2990_CONTROL        0x01
@@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
        int ret;
        struct device *hwmon_dev;
        struct ltc2990_data *data;
-       struct device_node *of_node = i2c->dev.of_node;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_WORD_DATA))
@@ -218,9 +217,10 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
 
        data->i2c = i2c;
 
-       if (of_node) {
-               ret = of_property_read_u32_array(of_node, "lltc,meas-mode",
-                                                data->mode, 2);
+       if (dev_fwnode(&i2c->dev)) {
+               ret = device_property_read_u32_array(&i2c->dev,
+                                                    "lltc,meas-mode",
+                                                    data->mode, 2);
                if (ret < 0)
                        return ret;
 
index d42bc08..7efa6bf 100644 (file)
@@ -20,6 +20,7 @@
  *
  * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
  * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
+ * nct6116d     9      5       5       3+3    0xd280 0xc1    0x5ca3
  * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
  * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
  * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
 
 #define USE_ALTERNATE
 
-enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
-            nct6795, nct6796, nct6797, nct6798 };
+enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
+            nct6793, nct6795, nct6796, nct6797, nct6798 };
 
 /* used to set data->name = nct6775_device_names[data->sio_kind] */
 static const char * const nct6775_device_names[] = {
        "nct6106",
+       "nct6116",
        "nct6775",
        "nct6776",
        "nct6779",
@@ -78,6 +80,7 @@ static const char * const nct6775_device_names[] = {
 
 static const char * const nct6775_sio_names[] __initconst = {
        "NCT6106D",
+       "NCT6116D",
        "NCT6775F",
        "NCT6776D/F",
        "NCT6779D",
@@ -115,6 +118,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
 #define SIO_NCT6106_ID         0xc450
+#define SIO_NCT6116_ID         0xd280
 #define SIO_NCT6775_ID         0xb470
 #define SIO_NCT6776_ID         0xc330
 #define SIO_NCT6779_ID         0xc560
@@ -825,10 +829,8 @@ static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
 
 static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
 static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
-static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
 static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
 static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
-static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
 static const u16 NCT6106_REG_TEMP_SOURCE[] = {
        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
 
@@ -896,6 +898,70 @@ static const u16 NCT6106_REG_TEMP_CRIT[32] = {
        [12] = 0x205,
 };
 
+/* NCT6112D/NCT6114D/NCT6116D specific data */
+
+static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
+static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
+static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
+static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
+
+static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
+static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
+static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
+static const u16 NCT6116_REG_TEMP_SOURCE[] = {
+       0xb0, 0xb1, 0xb2 };
+
+static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
+       0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
+static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
+       0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
+
+static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
+       0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
+static const u16 NCT6116_REG_CRITICAL_PWM[] = {
+       0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
+
+static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
+       0x114, 0x124, 0x134, 0x194, 0x1a4 };
+static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
+       0x115, 0x125, 0x135, 0x195, 0x1a5 };
+static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
+       0x116, 0x126, 0x136, 0x196, 0x1a6 };
+static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
+       0x117, 0x127, 0x137, 0x197, 0x1a7 };
+static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
+       0x118, 0x128, 0x138, 0x198, 0x1a8 };
+static const u16 NCT6116_REG_TOLERANCE_H[] = {
+       0x112, 0x122, 0x132, 0x192, 0x1a2 };
+
+static const u16 NCT6116_REG_TARGET[] = {
+       0x111, 0x121, 0x131, 0x191, 0x1a1 };
+
+static const u16 NCT6116_REG_AUTO_TEMP[] = {
+       0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
+static const u16 NCT6116_REG_AUTO_PWM[] = {
+       0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
+
+static const s8 NCT6116_ALARM_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, -1, -1, -1, -1, -1, -1,      /* in8..in9 */
+       -1,                             /* unused */
+       32, 33, 34, 35, 36,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, -1, -1, -1,         /* temp1..temp6 */
+       48, -1                          /* intrusion0, intrusion1 */
+};
+
+static const s8 NCT6116_BEEP_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, 10, 11, 12, -1, -1, -1,      /* in8..in14 */
+       32,                             /* global beep enable */
+       24, 25, 26, 27, 28,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, -1, -1, -1,         /* temp1..temp6 */
+       34, -1                          /* intrusion0, intrusion1 */
+};
+
 static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
 {
        if (mode == 0 && pwm == 255)
@@ -1294,6 +1360,11 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
                return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
                  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
                  reg == 0x111 || reg == 0x121 || reg == 0x131;
+       case nct6116:
+               return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+                 reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 ||
+                 reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 ||
+                 reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1;
        case nct6775:
                return (((reg & 0xff00) == 0x100 ||
                    (reg & 0xff00) == 0x200) &&
@@ -1673,6 +1744,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
                        data->auto_pwm[i][data->auto_pwm_num] = 0xff;
                        break;
                case nct6106:
+               case nct6116:
                case nct6779:
                case nct6791:
                case nct6792:
@@ -3109,6 +3181,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
                case nct6776:
                        break; /* always enabled, nothing to do */
                case nct6106:
+               case nct6116:
                case nct6779:
                case nct6791:
                case nct6792:
@@ -3535,6 +3608,23 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
 
                fan3pin = !(cr24 & 0x80);
                pwm3pin = cr24 & 0x08;
+       } else if (data->kind == nct6116) {
+               int cr1a = superio_inb(sioreg, 0x1a);
+               int cr1b = superio_inb(sioreg, 0x1b);
+               int cr24 = superio_inb(sioreg, 0x24);
+               int cr2a = superio_inb(sioreg, 0x2a);
+               int cr2b = superio_inb(sioreg, 0x2b);
+               int cr2f = superio_inb(sioreg, 0x2f);
+
+               fan3pin = !(cr2b & 0x10);
+               fan4pin = (cr2b & 0x80) ||                      // pin 1(2)
+                       (!(cr2f & 0x10) && (cr1a & 0x04));      // pin 65(66)
+               fan5pin = (cr2b & 0x80) ||                      // pin 126(127)
+                       (!(cr1b & 0x03) && (cr2a & 0x02));      // pin 94(96)
+
+               pwm3pin = fan3pin && (cr24 & 0x08);
+               pwm4pin = fan4pin;
+               pwm5pin = fan5pin;
        } else {
                /*
                 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
@@ -3765,7 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
                data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
-               data->REG_PWM[0] = NCT6106_REG_PWM;
+               data->REG_PWM[0] = NCT6116_REG_PWM;
                data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
                data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
                data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
@@ -3784,7 +3874,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
                data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
                data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
-               data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+               data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
                data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
                data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
                data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
@@ -3806,6 +3896,79 @@ static int nct6775_probe(struct platform_device *pdev)
                reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
                reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
 
+               break;
+       case nct6116:
+               data->in_num = 9;
+               data->pwm_num = 3;
+               data->auto_pwm_num = 4;
+               data->temp_fixed_num = 3;
+               data->num_temp_alarms = 3;
+               data->num_temp_beeps = 3;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+
+               data->temp_label = nct6776_temp_label;
+               data->temp_mask = NCT6776_TEMP_MASK;
+               data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
+
+               data->REG_VBAT = NCT6106_REG_VBAT;
+               data->REG_DIODE = NCT6106_REG_DIODE;
+               data->DIODE_MASK = NCT6106_DIODE_MASK;
+               data->REG_VIN = NCT6106_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+               data->REG_TARGET = NCT6116_REG_TARGET;
+               data->REG_FAN = NCT6116_REG_FAN;
+               data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
+               data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
+               data->REG_PWM[0] = NCT6116_REG_PWM;
+               data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
+               data->CRITICAL_PWM_ENABLE_MASK
+                 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+               data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
+               data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6106_REG_ALARM;
+               data->ALARM_BITS = NCT6116_ALARM_BITS;
+               data->REG_BEEP = NCT6106_REG_BEEP;
+               data->BEEP_BITS = NCT6116_BEEP_BITS;
+
+               reg_temp = NCT6106_REG_TEMP;
+               reg_temp_mon = NCT6106_REG_TEMP_MON;
+               num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+               num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
+               reg_temp_over = NCT6106_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+               reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+               reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+               reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
                break;
        case nct6775:
                data->in_num = 9;
@@ -4352,6 +4515,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->have_vid = (cr2a & 0x60) == 0x40;
                break;
        case nct6106:
+       case nct6116:
        case nct6779:
        case nct6791:
        case nct6792:
@@ -4381,6 +4545,7 @@ static int nct6775_probe(struct platform_device *pdev)
                                  NCT6775_REG_CR_FAN_DEBOUNCE);
                switch (data->kind) {
                case nct6106:
+               case nct6116:
                        tmp |= 0xe0;
                        break;
                case nct6775:
@@ -4576,6 +4741,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
        case SIO_NCT6106_ID:
                sio_data->kind = nct6106;
                break;
+       case SIO_NCT6116_ID:
+               sio_data->kind = nct6116;
+               break;
        case SIO_NCT6775_ID:
                sio_data->kind = nct6775;
                break;
index 710c305..95b447c 100644 (file)
 #define DTS_T_CTRL1_REG                0x27
 #define VT_ADC_MD_REG          0x2E
 
+#define VSEN1_HV_LL_REG                0x02    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_LV_LL_REG                0x03    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_HV_HL_REG                0x00    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define VSEN1_LV_HL_REG                0x01    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define SMI_STS1_REG           0xC1    /* Bank 0; SMI Status Register */
+#define SMI_STS3_REG           0xC3    /* Bank 0; SMI Status Register */
+#define SMI_STS5_REG           0xC5    /* Bank 0; SMI Status Register */
+#define SMI_STS7_REG           0xC7    /* Bank 0; SMI Status Register */
+#define SMI_STS8_REG           0xC8    /* Bank 0; SMI Status Register */
+
 #define VSEN1_HV_REG           0x40    /* Bank 0; 2 regs (HV/LV) per sensor */
 #define TEMP_CH1_HV_REG                0x42    /* Bank 0; same as VSEN2_HV */
 #define LTD_HV_REG             0x62    /* Bank 0; 2 regs in VSEN range */
+#define LTD_HV_HL_REG          0x44    /* Bank 1; 1 reg for LTD */
+#define LTD_LV_HL_REG          0x45    /* Bank 1; 1 reg for LTD */
+#define LTD_HV_LL_REG          0x46    /* Bank 1; 1 reg for LTD */
+#define LTD_LV_LL_REG          0x47    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_CH_REG                0x05    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_W_REG         0x06    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_WH_REG                0x07    /* Bank 1; 1 reg for LTD */
+#define TEMP_CH1_C_REG         0x04    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_C_REG       0x90    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_CH_REG      0x91    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_W_REG       0x92    /* Bank 1; 1 reg per sensor */
+#define DTS_T_CPU1_WH_REG      0x93    /* Bank 1; 1 reg per sensor */
 #define FANIN1_HV_REG          0x80    /* Bank 0; 2 regs (HV/LV) per sensor */
+#define FANIN1_HV_HL_REG       0x60    /* Bank 1; 2 regs (HV/LV) per sensor */
+#define FANIN1_LV_HL_REG       0x61    /* Bank 1; 2 regs (HV/LV) per sensor */
 #define T_CPU1_HV_REG          0xA0    /* Bank 0; 2 regs (HV/LV) per sensor */
 
 #define PRTS_REG               0x03    /* Bank 2 */
@@ -58,6 +82,8 @@
 #define FANCTL1_FMR_REG                0x00    /* Bank 3; 1 reg per channel */
 #define FANCTL1_OUT_REG                0x10    /* Bank 3; 1 reg per channel */
 
+#define ENABLE_TSI     BIT(1)
+
 static const unsigned short normal_i2c[] = {
        0x2d, 0x2e, I2C_CLIENT_END
 };
@@ -72,6 +98,7 @@ struct nct7904_data {
        u8 fan_mode[FANCTL_MAX];
        u8 enable_dts;
        u8 has_dts;
+       u8 temp_mode; /* 0: TR mode, 1: TD mode */
 };
 
 /* Access functions */
@@ -170,6 +197,25 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
                        rpm = 1350000 / cnt;
                *val = rpm;
                return 0;
+       case hwmon_fan_min:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        FANIN1_HV_HL_REG + channel * 2);
+               if (ret < 0)
+                       return ret;
+               cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
+               if (cnt == 0x1fff)
+                       rpm = 0;
+               else
+                       rpm = 1350000 / cnt;
+               *val = rpm;
+               return 0;
+       case hwmon_fan_alarm:
+               ret = nct7904_read_reg(data, BANK_0,
+                                      SMI_STS5_REG + (channel >> 3));
+               if (ret < 0)
+                       return ret;
+               *val = (ret >> (channel & 0x07)) & 1;
+               return 0;
        default:
                return -EOPNOTSUPP;
        }
@@ -179,8 +225,20 @@ static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel)
 {
        const struct nct7904_data *data = _data;
 
-       if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel))
-               return 0444;
+       switch (attr) {
+       case hwmon_fan_input:
+       case hwmon_fan_alarm:
+               if (data->fanin_mask & (1 << channel))
+                       return 0444;
+               break;
+       case hwmon_fan_min:
+               if (data->fanin_mask & (1 << channel))
+                       return 0644;
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
 
@@ -211,6 +269,37 @@ static int nct7904_read_in(struct device *dev, u32 attr, int channel,
                        volt *= 6; /* 0.006V scale */
                *val = volt;
                return 0;
+       case hwmon_in_min:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        VSEN1_HV_LL_REG + index * 4);
+               if (ret < 0)
+                       return ret;
+               volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
+               if (index < 14)
+                       volt *= 2; /* 0.002V scale */
+               else
+                       volt *= 6; /* 0.006V scale */
+               *val = volt;
+               return 0;
+       case hwmon_in_max:
+               ret = nct7904_read_reg16(data, BANK_1,
+                                        VSEN1_HV_HL_REG + index * 4);
+               if (ret < 0)
+                       return ret;
+               volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
+               if (index < 14)
+                       volt *= 2; /* 0.002V scale */
+               else
+                       volt *= 6; /* 0.006V scale */
+               *val = volt;
+               return 0;
+       case hwmon_in_alarm:
+               ret = nct7904_read_reg(data, BANK_0,
+                                      SMI_STS1_REG + (index >> 3));
+               if (ret < 0)
+                       return ret;
+               *val = (ret >> (index & 0x07)) & 1;
+               return 0;
        default:
                return -EOPNOTSUPP;
        }
@@ -221,9 +310,20 @@ static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel)
        const struct nct7904_data *data = _data;
        int index = nct7904_chan_to_index[channel];
 
-       if (channel > 0 && attr == hwmon_in_input &&
-           (data->vsen_mask & BIT(index)))
-               return 0444;
+       switch (attr) {
+       case hwmon_in_input:
+       case hwmon_in_alarm:
+               if (channel > 0 && (data->vsen_mask & BIT(index)))
+                       return 0444;
+               break;
+       case hwmon_in_min:
+       case hwmon_in_max:
+               if (channel > 0 && (data->vsen_mask & BIT(index)))
+                       return 0644;
+               break;
+       default:
+               break;
+       }
 
        return 0;
 }
@@ -233,6 +333,7 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
 {
        struct nct7904_data *data = dev_get_drvdata(dev);
        int ret, temp;
+       unsigned int reg1, reg2, reg3;
 
        switch (attr) {
        case hwmon_temp_input:
@@ -250,16 +351,106 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
                temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
                *val = sign_extend32(temp, 10) * 125;
                return 0;
+       case hwmon_temp_alarm:
+               if (channel == 4) {
+                       ret = nct7904_read_reg(data, BANK_0,
+                                              SMI_STS3_REG);
+                       if (ret < 0)
+                               return ret;
+                       *val = (ret >> 1) & 1;
+               } else if (channel < 4) {
+                       ret = nct7904_read_reg(data, BANK_0,
+                                              SMI_STS1_REG);
+                       if (ret < 0)
+                               return ret;
+                       *val = (ret >> (((channel * 2) + 1) & 0x07)) & 1;
+               } else {
+                       if ((channel - 5) < 4) {
+                               ret = nct7904_read_reg(data, BANK_0,
+                                                      SMI_STS7_REG +
+                                                      ((channel - 5) >> 3));
+                               if (ret < 0)
+                                       return ret;
+                               *val = (ret >> ((channel - 5) & 0x07)) & 1;
+                       } else {
+                               ret = nct7904_read_reg(data, BANK_0,
+                                                      SMI_STS8_REG +
+                                                      ((channel - 5) >> 3));
+                               if (ret < 0)
+                                       return ret;
+                               *val = (ret >> (((channel - 5) & 0x07) - 4))
+                                                       & 1;
+                       }
+               }
+               return 0;
+       case hwmon_temp_type:
+               if (channel < 5) {
+                       if ((data->tcpu_mask >> channel) & 0x01) {
+                               if ((data->temp_mode >> channel) & 0x01)
+                                       *val = 3; /* TD */
+                               else
+                                       *val = 4; /* TR */
+                       } else {
+                               *val = 0;
+                       }
+               } else {
+                       if ((data->has_dts >> (channel - 5)) & 0x01) {
+                               if (data->enable_dts & ENABLE_TSI)
+                                       *val = 5; /* TSI */
+                               else
+                                       *val = 6; /* PECI */
+                       } else {
+                               *val = 0;
+                       }
+               }
+               return 0;
+       case hwmon_temp_max:
+               reg1 = LTD_HV_LL_REG;
+               reg2 = TEMP_CH1_W_REG;
+               reg3 = DTS_T_CPU1_W_REG;
+               break;
+       case hwmon_temp_max_hyst:
+               reg1 = LTD_LV_LL_REG;
+               reg2 = TEMP_CH1_WH_REG;
+               reg3 = DTS_T_CPU1_WH_REG;
+               break;
+       case hwmon_temp_crit:
+               reg1 = LTD_HV_HL_REG;
+               reg2 = TEMP_CH1_C_REG;
+               reg3 = DTS_T_CPU1_C_REG;
+               break;
+       case hwmon_temp_crit_hyst:
+               reg1 = LTD_LV_HL_REG;
+               reg2 = TEMP_CH1_CH_REG;
+               reg3 = DTS_T_CPU1_CH_REG;
+               break;
        default:
                return -EOPNOTSUPP;
        }
+
+       if (channel == 4)
+               ret = nct7904_read_reg(data, BANK_1, reg1);
+       else if (channel < 5)
+               ret = nct7904_read_reg(data, BANK_1,
+                                      reg2 + channel * 8);
+       else
+               ret = nct7904_read_reg(data, BANK_1,
+                                      reg3 + (channel - 5) * 4);
+
+       if (ret < 0)
+               return ret;
+       *val = ret * 1000;
+       return 0;
 }
 
 static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
 {
        const struct nct7904_data *data = _data;
 
-       if (attr == hwmon_temp_input) {
+       switch (attr) {
+       case hwmon_temp_input:
+       case hwmon_temp_alarm:
+       case hwmon_temp_type:
                if (channel < 5) {
                        if (data->tcpu_mask & BIT(channel))
                                return 0444;
@@ -267,6 +458,21 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
                        if (data->has_dts & BIT(channel - 5))
                                return 0444;
                }
+               break;
+       case hwmon_temp_max:
+       case hwmon_temp_max_hyst:
+       case hwmon_temp_crit:
+       case hwmon_temp_crit_hyst:
+               if (channel < 5) {
+                       if (data->tcpu_mask & BIT(channel))
+                               return 0644;
+               } else {
+                       if (data->has_dts & BIT(channel - 5))
+                               return 0644;
+               }
+               break;
+       default:
+               break;
        }
 
        return 0;
@@ -297,6 +503,137 @@ static int nct7904_read_pwm(struct device *dev, u32 attr, int channel,
        }
 }
 
+static int nct7904_write_temp(struct device *dev, u32 attr, int channel,
+                             long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret;
+       unsigned int reg1, reg2, reg3;
+
+       val = clamp_val(val / 1000, -128, 127);
+
+       switch (attr) {
+       case hwmon_temp_max:
+               reg1 = LTD_HV_LL_REG;
+               reg2 = TEMP_CH1_W_REG;
+               reg3 = DTS_T_CPU1_W_REG;
+               break;
+       case hwmon_temp_max_hyst:
+               reg1 = LTD_LV_LL_REG;
+               reg2 = TEMP_CH1_WH_REG;
+               reg3 = DTS_T_CPU1_WH_REG;
+               break;
+       case hwmon_temp_crit:
+               reg1 = LTD_HV_HL_REG;
+               reg2 = TEMP_CH1_C_REG;
+               reg3 = DTS_T_CPU1_C_REG;
+               break;
+       case hwmon_temp_crit_hyst:
+               reg1 = LTD_LV_HL_REG;
+               reg2 = TEMP_CH1_CH_REG;
+               reg3 = DTS_T_CPU1_CH_REG;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       if (channel == 4)
+               ret = nct7904_write_reg(data, BANK_1, reg1, val);
+       else if (channel < 5)
+               ret = nct7904_write_reg(data, BANK_1,
+                                       reg2 + channel * 8, val);
+       else
+               ret = nct7904_write_reg(data, BANK_1,
+                                       reg3 + (channel - 5) * 4, val);
+
+       return ret;
+}
+
+static int nct7904_write_fan(struct device *dev, u32 attr, int channel,
+                            long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret;
+       u8 tmp;
+
+       switch (attr) {
+       case hwmon_fan_min:
+               if (val <= 0)
+                       return -EINVAL;
+
+               val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), 1, 0x1fff);
+               tmp = (val >> 5) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       FANIN1_HV_HL_REG + channel * 2, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = val & 0x1f;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       FANIN1_LV_HL_REG + channel * 2, tmp);
+               return ret;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int nct7904_write_in(struct device *dev, u32 attr, int channel,
+                           long val)
+{
+       struct nct7904_data *data = dev_get_drvdata(dev);
+       int ret, index, tmp;
+
+       index = nct7904_chan_to_index[channel];
+
+       if (index < 14)
+               val = val / 2; /* 0.002V scale */
+       else
+               val = val / 6; /* 0.006V scale */
+
+       val = clamp_val(val, 0, 0x7ff);
+
+       switch (attr) {
+       case hwmon_in_min:
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_LV_LL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp &= ~0x7;
+               tmp |= val & 0x7;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_LV_LL_REG + index * 4, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_HV_LL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp = (val >> 3) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_HV_LL_REG + index * 4, tmp);
+               return ret;
+       case hwmon_in_max:
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_LV_HL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp &= ~0x7;
+               tmp |= val & 0x7;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_LV_HL_REG + index * 4, tmp);
+               if (ret < 0)
+                       return ret;
+               tmp = nct7904_read_reg(data, BANK_1,
+                                      VSEN1_HV_HL_REG + index * 4);
+               if (tmp < 0)
+                       return tmp;
+               tmp = (val >> 3) & 0xff;
+               ret = nct7904_write_reg(data, BANK_1,
+                                       VSEN1_HV_HL_REG + index * 4, tmp);
+               return ret;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static int nct7904_write_pwm(struct device *dev, u32 attr, int channel,
                             long val)
 {
@@ -354,8 +691,14 @@ static int nct7904_write(struct device *dev, enum hwmon_sensor_types type,
                         u32 attr, int channel, long val)
 {
        switch (type) {
+       case hwmon_in:
+               return nct7904_write_in(dev, attr, channel, val);
+       case hwmon_fan:
+               return nct7904_write_fan(dev, attr, channel, val);
        case hwmon_pwm:
                return nct7904_write_pwm(dev, attr, channel, val);
+       case hwmon_temp:
+               return nct7904_write_temp(dev, attr, channel, val);
        default:
                return -EOPNOTSUPP;
        }
@@ -404,51 +747,91 @@ static int nct7904_detect(struct i2c_client *client,
 
 static const struct hwmon_channel_info *nct7904_info[] = {
        HWMON_CHANNEL_INFO(in,
-                          HWMON_I_INPUT, /* dummy, skipped in is_visible */
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT,
-                          HWMON_I_INPUT),
+                          /* dummy, skipped in is_visible */
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM,
+                          HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
+                          HWMON_I_ALARM),
        HWMON_CHANNEL_INFO(fan,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT,
-                          HWMON_F_INPUT),
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM),
        HWMON_CHANNEL_INFO(pwm,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
        HWMON_CHANNEL_INFO(temp,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT,
-                          HWMON_T_INPUT),
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST),
        NULL
 };
 
@@ -530,11 +913,14 @@ static int nct7904_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
+       data->temp_mode = 0;
        for (i = 0; i < 4; i++) {
                val = (ret & (0x03 << i)) >> (i * 2);
                bit = (1 << i);
                if (val == 0)
                        data->tcpu_mask &= ~bit;
+               else if (val == 0x1 || val == 0x2)
+                       data->temp_mode |= bit;
        }
 
        /* PECI */
@@ -557,7 +943,7 @@ static int nct7904_probe(struct i2c_client *client,
                if (ret < 0)
                        return ret;
                data->has_dts = ret & 0xF;
-               if (data->enable_dts & 0x2) {
+               if (data->enable_dts & ENABLE_TSI) {
                        ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
                        if (ret < 0)
                                return ret;
index 09aaefa..11a2860 100644 (file)
@@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
                spin_lock_init(&data->fan_lock[i]);
 
                data->fan_irq[i] = platform_get_irq(pdev, i);
-               if (data->fan_irq[i] < 0) {
-                       dev_err(dev, "get IRQ fan%d failed\n", i);
+               if (data->fan_irq[i] < 0)
                        return data->fan_irq[i];
-               }
 
                sprintf(name, "NPCM7XX-FAN-MD%d", i);
                ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr,
index b658848..d62d69b 100644 (file)
@@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS
          This driver can also be built as a module. If so, the module will
          be called ibm-cffps.
 
+config SENSORS_INSPUR_IPSPS
+       tristate "INSPUR Power System Power Supply"
+       help
+         If you say yes here you get hardware monitoring support for the INSPUR
+         Power System power supply.
+
+         This driver can also be built as a module. If so, the module will
+         be called inspur-ipsps.
+
 config SENSORS_IR35221
        tristate "Infineon IR35221"
        help
index c950ea9..03bacfc 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS)             += pmbus_core.o
 obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
 obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
 obj-$(CONFIG_SENSORS_IBM_CFFPS)        += ibm-cffps.o
+obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
 obj-$(CONFIG_SENSORS_IR35221)  += ir35221.o
 obj-$(CONFIG_SENSORS_IR38064)  += ir38064.o
 obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
index ee2ee9e..d44745e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/of_device.h>
 #include <linux/pmbus.h>
 
 #include "pmbus.h"
@@ -20,8 +21,9 @@
 #define CFFPS_PN_CMD                           0x9B
 #define CFFPS_SN_CMD                           0x9E
 #define CFFPS_CCIN_CMD                         0xBD
-#define CFFPS_FW_CMD_START                     0xFA
-#define CFFPS_FW_NUM_BYTES                     4
+#define CFFPS_FW_CMD                           0xFA
+#define CFFPS1_FW_NUM_BYTES                    4
+#define CFFPS2_FW_NUM_WORDS                    3
 #define CFFPS_SYS_CONFIG_CMD                   0xDA
 
 #define CFFPS_INPUT_HISTORY_CMD                        0xD6
@@ -52,6 +54,8 @@ enum {
        CFFPS_DEBUGFS_NUM_ENTRIES
 };
 
+enum versions { cffps1, cffps2 };
+
 struct ibm_cffps_input_history {
        struct mutex update_lock;
        unsigned long last_update;
@@ -61,6 +65,7 @@ struct ibm_cffps_input_history {
 };
 
 struct ibm_cffps {
+       enum versions version;
        struct i2c_client *client;
 
        struct ibm_cffps_input_history input_history;
@@ -132,6 +137,8 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
        struct ibm_cffps *psu = to_psu(idxp, idx);
        char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
 
+       pmbus_set_page(psu->client, 0);
+
        switch (idx) {
        case CFFPS_DEBUGFS_INPUT_HISTORY:
                return ibm_cffps_read_input_history(psu, buf, count, ppos);
@@ -152,16 +159,36 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
                rc = snprintf(data, 5, "%04X", rc);
                goto done;
        case CFFPS_DEBUGFS_FW:
-               for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) {
-                       rc = i2c_smbus_read_byte_data(psu->client,
-                                                     CFFPS_FW_CMD_START + i);
-                       if (rc < 0)
-                               return rc;
+               switch (psu->version) {
+               case cffps1:
+                       for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
+                               rc = i2c_smbus_read_byte_data(psu->client,
+                                                             CFFPS_FW_CMD +
+                                                               i);
+                               if (rc < 0)
+                                       return rc;
+
+                               snprintf(&data[i * 2], 3, "%02X", rc);
+                       }
 
-                       snprintf(&data[i * 2], 3, "%02X", rc);
-               }
+                       rc = i * 2;
+                       break;
+               case cffps2:
+                       for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) {
+                               rc = i2c_smbus_read_word_data(psu->client,
+                                                             CFFPS_FW_CMD +
+                                                               i);
+                               if (rc < 0)
+                                       return rc;
+
+                               snprintf(&data[i * 4], 5, "%04X", rc);
+                       }
 
-               rc = i * 2;
+                       rc = i * 4;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
                goto done;
        default:
                return -EINVAL;
@@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
                        psu->led_state = CFFPS_LED_ON;
        }
 
+       pmbus_set_page(psu->client, 0);
+
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       psu->led_state);
        if (rc < 0)
@@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
        if (led_cdev->brightness == LED_OFF)
                return 0;
 
+       pmbus_set_page(psu->client, 0);
+
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       CFFPS_LED_BLINK);
        if (rc < 0)
@@ -328,15 +359,32 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
                dev_warn(dev, "failed to register led class: %d\n", rc);
 }
 
-static struct pmbus_driver_info ibm_cffps_info = {
-       .pages = 1,
-       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
-               PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
-               PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
-               PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
-               PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
-       .read_byte_data = ibm_cffps_read_byte_data,
-       .read_word_data = ibm_cffps_read_word_data,
+static struct pmbus_driver_info ibm_cffps_info[] = {
+       [cffps1] = {
+               .pages = 1,
+               .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
+                       PMBUS_HAVE_STATUS_FAN12,
+               .read_byte_data = ibm_cffps_read_byte_data,
+               .read_word_data = ibm_cffps_read_word_data,
+       },
+       [cffps2] = {
+               .pages = 2,
+               .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
+                       PMBUS_HAVE_STATUS_FAN12,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+                       PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+                       PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
+               .read_byte_data = ibm_cffps_read_byte_data,
+               .read_word_data = ibm_cffps_read_word_data,
+       },
 };
 
 static struct pmbus_platform_data ibm_cffps_pdata = {
@@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
        int i, rc;
+       enum versions vs;
        struct dentry *debugfs;
        struct dentry *ibm_cffps_dir;
        struct ibm_cffps *psu;
+       const void *md = of_device_get_match_data(&client->dev);
+
+       if (md)
+               vs = (enum versions)md;
+       else if (id)
+               vs = (enum versions)id->driver_data;
+       else
+               vs = cffps1;
 
        client->dev.platform_data = &ibm_cffps_pdata;
-       rc = pmbus_do_probe(client, id, &ibm_cffps_info);
+       rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
        if (rc)
                return rc;
 
@@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
        if (!psu)
                return 0;
 
+       psu->version = vs;
        psu->client = client;
        mutex_init(&psu->input_history.update_lock);
        psu->input_history.last_update = jiffies - HZ;
@@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id ibm_cffps_id[] = {
-       { "ibm_cffps1", 1 },
+       { "ibm_cffps1", cffps1 },
+       { "ibm_cffps2", cffps2 },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
 
 static const struct of_device_id ibm_cffps_of_match[] = {
-       { .compatible = "ibm,cffps1" },
+       {
+               .compatible = "ibm,cffps1",
+               .data = (void *)cffps1
+       },
+       {
+               .compatible = "ibm,cffps2",
+               .data = (void *)cffps2
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c
new file mode 100644 (file)
index 0000000..42e0154
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Inspur Corp.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pmbus.h>
+#include <linux/hwmon-sysfs.h>
+
+#include "pmbus.h"
+
+#define IPSPS_REG_VENDOR_ID    0x99
+#define IPSPS_REG_MODEL                0x9A
+#define IPSPS_REG_FW_VERSION   0x9B
+#define IPSPS_REG_PN           0x9C
+#define IPSPS_REG_SN           0x9E
+#define IPSPS_REG_HW_VERSION   0xB0
+#define IPSPS_REG_MODE         0xFC
+
+#define MODE_ACTIVE            0x55
+#define MODE_STANDBY           0x0E
+#define MODE_REDUNDANCY                0x00
+
+#define MODE_ACTIVE_STRING             "active"
+#define MODE_STANDBY_STRING            "standby"
+#define MODE_REDUNDANCY_STRING         "redundancy"
+
+enum ipsps_index {
+       vendor,
+       model,
+       fw_version,
+       part_number,
+       serial_number,
+       hw_version,
+       mode,
+       num_regs,
+};
+
+static const u8 ipsps_regs[num_regs] = {
+       [vendor] = IPSPS_REG_VENDOR_ID,
+       [model] = IPSPS_REG_MODEL,
+       [fw_version] = IPSPS_REG_FW_VERSION,
+       [part_number] = IPSPS_REG_PN,
+       [serial_number] = IPSPS_REG_SN,
+       [hw_version] = IPSPS_REG_HW_VERSION,
+       [mode] = IPSPS_REG_MODE,
+};
+
+static ssize_t ipsps_string_show(struct device *dev,
+                                struct device_attribute *devattr,
+                                char *buf)
+{
+       u8 reg;
+       int rc;
+       char *p;
+       char data[I2C_SMBUS_BLOCK_MAX + 1];
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_block_data(client, reg, data);
+       if (rc < 0)
+               return rc;
+
+       /* filled with printable characters, ending with # */
+       p = memscan(data, '#', rc);
+       *p = '\0';
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", data);
+}
+
+static ssize_t ipsps_fw_version_show(struct device *dev,
+                                    struct device_attribute *devattr,
+                                    char *buf)
+{
+       u8 reg;
+       int rc;
+       u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 };
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_block_data(client, reg, data);
+       if (rc < 0)
+               return rc;
+
+       if (rc != 6)
+               return -EPROTO;
+
+       return snprintf(buf, PAGE_SIZE, "%u.%02u%u-%u.%02u\n",
+                       data[1], data[2]/* < 100 */, data[3]/*< 10*/,
+                       data[4], data[5]/* < 100 */);
+}
+
+static ssize_t ipsps_mode_show(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       u8 reg;
+       int rc;
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       rc = i2c_smbus_read_byte_data(client, reg);
+       if (rc < 0)
+               return rc;
+
+       switch (rc) {
+       case MODE_ACTIVE:
+               return snprintf(buf, PAGE_SIZE, "[%s] %s %s\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       case MODE_STANDBY:
+               return snprintf(buf, PAGE_SIZE, "%s [%s] %s\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       case MODE_REDUNDANCY:
+               return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n",
+                               MODE_ACTIVE_STRING,
+                               MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+       default:
+               return snprintf(buf, PAGE_SIZE, "unspecified\n");
+       }
+}
+
+static ssize_t ipsps_mode_store(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       u8 reg;
+       int rc;
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       reg = ipsps_regs[attr->index];
+       if (sysfs_streq(MODE_STANDBY_STRING, buf)) {
+               rc = i2c_smbus_write_byte_data(client, reg,
+                                              MODE_STANDBY);
+               if (rc < 0)
+                       return rc;
+               return count;
+       } else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) {
+               rc = i2c_smbus_write_byte_data(client, reg,
+                                              MODE_ACTIVE);
+               if (rc < 0)
+                       return rc;
+               return count;
+       }
+
+       return -EINVAL;
+}
+
+static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor);
+static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model);
+static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number);
+static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number);
+static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version);
+static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version);
+static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode);
+
+static struct attribute *ipsps_attrs[] = {
+       &sensor_dev_attr_vendor.dev_attr.attr,
+       &sensor_dev_attr_model.dev_attr.attr,
+       &sensor_dev_attr_part_number.dev_attr.attr,
+       &sensor_dev_attr_serial_number.dev_attr.attr,
+       &sensor_dev_attr_hw_version.dev_attr.attr,
+       &sensor_dev_attr_fw_version.dev_attr.attr,
+       &sensor_dev_attr_mode.dev_attr.attr,
+       NULL,
+};
+
+ATTRIBUTE_GROUPS(ipsps);
+
+static struct pmbus_driver_info ipsps_info = {
+       .pages = 1,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+               PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN |
+               PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
+               PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
+               PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
+               PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
+       .groups = ipsps_groups,
+};
+
+static struct pmbus_platform_data ipsps_pdata = {
+       .flags = PMBUS_SKIP_STATUS_CHECK,
+};
+
+static int ipsps_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       client->dev.platform_data = &ipsps_pdata;
+       return pmbus_do_probe(client, id, &ipsps_info);
+}
+
+static const struct i2c_device_id ipsps_id[] = {
+       { "ipsps1", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ipsps_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ipsps_of_match[] = {
+       { .compatible = "inspur,ipsps1" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ipsps_of_match);
+#endif
+
+static struct i2c_driver ipsps_driver = {
+       .driver = {
+               .name = "inspur-ipsps",
+               .of_match_table = of_match_ptr(ipsps_of_match),
+       },
+       .probe = ipsps_probe,
+       .remove = pmbus_do_remove,
+       .id_table = ipsps_id,
+};
+
+module_i2c_driver(ipsps_driver);
+
+MODULE_AUTHOR("John Wang");
+MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
+MODULE_LICENSE("GPL");
index 69d9029..254b0f9 100644 (file)
@@ -244,8 +244,6 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
 #define MAX31785_VOUT_FUNCS \
        (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
 
-#define MAX37185_NUM_FAN_PAGES 6
-
 static const struct pmbus_driver_info max31785_info = {
        .pages = MAX31785_NR_PAGES,
 
index c846759..a9229c6 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/pmbus.h>
-#include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include "pmbus.h"
 
index efe4bb1..d3a64a3 100644 (file)
@@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = {
 };
 module_platform_driver(rpi_hwmon_driver);
 
-MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
+MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>");
 MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:raspberrypi-hwmon");
index 83fe081..a0078cc 100644 (file)
@@ -24,19 +24,33 @@ static const unsigned char shtc1_cmd_measure_blocking_lpm[]    = { 0x64, 0x58 };
 static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
 
 /* command for reading the ID register */
-static const unsigned char shtc1_cmd_read_id_reg[]            = { 0xef, 0xc8 };
+static const unsigned char shtc1_cmd_read_id_reg[]             = { 0xef, 0xc8 };
 
-/* constants for reading the ID register */
-#define SHTC1_ID         0x07
-#define SHTC1_ID_REG_MASK 0x1f
+/*
+ * constants for reading the ID register
+ * SHTC1: 0x0007 with mask 0x003f
+ * SHTW1: 0x0007 with mask 0x003f
+ * SHTC3: 0x0807 with mask 0x083f
+ */
+#define SHTC3_ID      0x0807
+#define SHTC3_ID_MASK 0x083f
+#define SHTC1_ID      0x0007
+#define SHTC1_ID_MASK 0x003f
 
 /* delays for non-blocking i2c commands, both in us */
 #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
 #define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
+#define SHTC3_NONBLOCKING_WAIT_TIME_HPM  12100
+#define SHTC3_NONBLOCKING_WAIT_TIME_LPM    800
 
 #define SHTC1_CMD_LENGTH      2
 #define SHTC1_RESPONSE_LENGTH 6
 
+enum shtcx_chips {
+       shtc1,
+       shtc3,
+};
+
 struct shtc1_data {
        struct i2c_client *client;
        struct mutex update_lock;
@@ -47,6 +61,7 @@ struct shtc1_data {
        unsigned int nonblocking_wait_time; /* in us */
 
        struct shtc1_platform_data setup;
+       enum shtcx_chips chip;
 
        int temperature; /* 1000 * temperature in dgr C */
        int humidity; /* 1000 * relative humidity in %RH */
@@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data)
                data->command = data->setup.blocking_io ?
                                shtc1_cmd_measure_blocking_hpm :
                                shtc1_cmd_measure_nonblocking_hpm;
-               data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM;
-
+               data->nonblocking_wait_time = (data->chip == shtc1) ?
+                               SHTC1_NONBLOCKING_WAIT_TIME_HPM :
+                               SHTC3_NONBLOCKING_WAIT_TIME_HPM;
        } else {
                data->command = data->setup.blocking_io ?
                                shtc1_cmd_measure_blocking_lpm :
                                shtc1_cmd_measure_nonblocking_lpm;
-               data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM;
+               data->nonblocking_wait_time = (data->chip == shtc1) ?
+                               SHTC1_NONBLOCKING_WAIT_TIME_LPM :
+                               SHTC3_NONBLOCKING_WAIT_TIME_LPM;
        }
 }
 
@@ -171,9 +189,11 @@ static int shtc1_probe(struct i2c_client *client,
                       const struct i2c_device_id *id)
 {
        int ret;
-       char id_reg[2];
+       u16 id_reg;
+       char id_reg_buf[2];
        struct shtc1_data *data;
        struct device *hwmon_dev;
+       enum shtcx_chips chip = id->driver_data;
        struct i2c_adapter *adap = client->adapter;
        struct device *dev = &client->dev;
 
@@ -187,13 +207,20 @@ static int shtc1_probe(struct i2c_client *client,
                dev_err(dev, "could not send read_id_reg command: %d\n", ret);
                return ret < 0 ? ret : -ENODEV;
        }
-       ret = i2c_master_recv(client, id_reg, sizeof(id_reg));
-       if (ret != sizeof(id_reg)) {
+       ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
+       if (ret != sizeof(id_reg_buf)) {
                dev_err(dev, "could not read ID register: %d\n", ret);
                return -ENODEV;
        }
-       if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) {
-               dev_err(dev, "ID register doesn't match\n");
+
+       id_reg = be16_to_cpup((__be16 *)id_reg_buf);
+       if (chip == shtc3) {
+               if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {
+                       dev_err(dev, "SHTC3 ID register does not match\n");
+                       return -ENODEV;
+               }
+       } else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {
+               dev_err(dev, "SHTC1 ID register does not match\n");
                return -ENODEV;
        }
 
@@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client,
        data->setup.blocking_io = false;
        data->setup.high_precision = true;
        data->client = client;
+       data->chip = chip;
 
        if (client->dev.platform_data)
                data->setup = *(struct shtc1_platform_data *)dev->platform_data;
@@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client,
 
 /* device ID table */
 static const struct i2c_device_id shtc1_id[] = {
-       { "shtc1", 0 },
-       { "shtw1", 0 },
+       { "shtc1", shtc1 },
+       { "shtw1", shtc1 },
+       { "shtc3", shtc3 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, shtc1_id);
index d8c91c2..6eff14f 100644 (file)
@@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client,
 
        data->client = client;
        data->type = id->driver_data;
-       data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK)
+       data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK)
                                     | SMM665_CMDREG_BASE);
-       if (!data->cmdreg)
-               return -ENOMEM;
+       if (IS_ERR(data->cmdreg))
+               return PTR_ERR(data->cmdreg);
 
        switch (data->type) {
        case smm465:
index d2c04b6..015f1ea 100644 (file)
@@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client)
        }
 
        for (i = 0; i < num_sc; i++) {
-               data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
-               if (!data->lm75[i]) {
+               data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]);
+               if (IS_ERR(data->lm75[i])) {
                        dev_err(&new_client->dev,
                                "Subclient %d registration at address 0x%x failed.\n",
                                i, sc_addr[i]);
-                       err = -ENOMEM;
+                       err = PTR_ERR(data->lm75[i]);
                        if (i == 1)
                                goto ERROR_SC_3;
                        goto ERROR_SC_2;
index 050ad42..aad8d4d 100644 (file)
@@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
        struct i2c_adapter *adapter = client->adapter;
        struct w83791d_data *data = i2c_get_clientdata(client);
        int address = client->addr;
-       int i, id, err;
+       int i, id;
        u8 val;
 
        id = i2c_adapter_id(adapter);
@@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
                                        "invalid subclient "
                                        "address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -ENODEV;
-                               goto error_sc_0;
+                               return -ENODEV;
                        }
                }
                w83791d_write(client, W83791D_REG_I2C_SUBADDR,
@@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client)
 
        val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
        if (!(val & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + (val & 0x7));
        if (!(val & 0x80)) {
-               if ((data->lm75[0] != NULL) &&
+               if (!IS_ERR(data->lm75[0]) &&
                                ((val & 0x7) == ((val >> 4) & 0x7))) {
                        dev_err(&client->dev,
                                "duplicate addresses 0x%x, "
                                "use force_subclient\n",
                                data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto error_sc_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((val >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + ((val >> 4) & 0x7));
        }
 
        return 0;
-
-/* Undo inits in case of errors */
-
-error_sc_1:
-       i2c_unregister_device(data->lm75[0]);
-error_sc_0:
-       return err;
 }
 
 
@@ -1394,7 +1386,7 @@ static int w83791d_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &w83791d_group);
        if (err)
-               goto error3;
+               return err;
 
        /* Check if pins of fan/pwm 4-5 are in use as GPIO */
        has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10;
@@ -1419,9 +1411,6 @@ error5:
                sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
 error4:
        sysfs_remove_group(&client->dev.kobj, &w83791d_group);
-error3:
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
        return err;
 }
 
@@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &w83791d_group);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        return 0;
 }
 
index da8a6d6..7fc8a11 100644 (file)
@@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
 static int
 w83792d_detect_subclients(struct i2c_client *new_client)
 {
-       int i, id, err;
+       int i, id;
        int address = new_client->addr;
        u8 val;
        struct i2c_adapter *adapter = new_client->adapter;
@@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client)
                                dev_err(&new_client->dev,
                                        "invalid subclient address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -ENODEV;
-                               goto ERROR_SC_0;
+                               return -ENODEV;
                        }
                }
                w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
@@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client)
 
        val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
        if (!(val & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
+                                                         0x48 + (val & 0x7));
        if (!(val & 0x80)) {
-               if ((data->lm75[0] != NULL) &&
+               if (!IS_ERR(data->lm75[0]) &&
                        ((val & 0x7) == ((val >> 4) & 0x7))) {
                        dev_err(&new_client->dev,
                                "duplicate addresses 0x%x, use force_subclient\n",
                                data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto ERROR_SC_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((val >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
+                                                         0x48 + ((val >> 4) & 0x7));
        }
 
        return 0;
-
-/* Undo inits in case of errors */
-
-ERROR_SC_1:
-       i2c_unregister_device(data->lm75[0]);
-ERROR_SC_0:
-       return err;
 }
 
 static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
@@ -1396,7 +1388,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Register sysfs hooks */
        err = sysfs_create_group(&dev->kobj, &w83792d_group);
        if (err)
-               goto exit_i2c_unregister;
+               return err;
 
        /*
         * Read GPIO enable register to check if pins for fan 4,5 are used as
@@ -1441,9 +1433,6 @@ exit_remove_files:
        sysfs_remove_group(&dev->kobj, &w83792d_group);
        for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
                sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
-exit_i2c_unregister:
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
        return err;
 }
 
@@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client)
                sysfs_remove_group(&client->dev.kobj,
                                   &w83792d_group_fan[i]);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        return 0;
 }
 
index 46f5dfe..9df48b7 100644 (file)
@@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client)
        for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
                device_remove_file(dev, &w83793_temp[i].dev_attr);
 
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
-
        /* Decrease data reference counter */
        mutex_lock(&watchdog_data_mutex);
        kref_put(&data->kref, w83793_release_resources);
@@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client)
 static int
 w83793_detect_subclients(struct i2c_client *client)
 {
-       int i, id, err;
+       int i, id;
        int address = client->addr;
        u8 tmp;
        struct i2c_adapter *adapter = client->adapter;
@@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client)
                                        "invalid subclient "
                                        "address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
-                               err = -EINVAL;
-                               goto ERROR_SC_0;
+                               return -EINVAL;
                        }
                }
                w83793_write_value(client, W83793_REG_I2C_SUBADDR,
@@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client)
 
        tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
        if (!(tmp & 0x08))
-               data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
+               data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + (tmp & 0x7));
        if (!(tmp & 0x80)) {
-               if ((data->lm75[0] != NULL)
+               if (!IS_ERR(data->lm75[0])
                    && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
                        dev_err(&client->dev,
                                "duplicate addresses 0x%x, "
                                "use force_subclients\n", data->lm75[0]->addr);
-                       err = -ENODEV;
-                       goto ERROR_SC_1;
+                       return -ENODEV;
                }
-               data->lm75[1] = i2c_new_dummy(adapter,
-                                             0x48 + ((tmp >> 4) & 0x7));
+               data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
+                                                         0x48 + ((tmp >> 4) & 0x7));
        }
 
        return 0;
-
-       /* Undo inits in case of errors */
-
-ERROR_SC_1:
-       i2c_unregister_device(data->lm75[0]);
-ERROR_SC_0:
-       return err;
 }
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
@@ -1945,9 +1934,6 @@ exit_remove:
 
        for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
                device_remove_file(dev, &w83793_temp[i].dev_attr);
-
-       i2c_unregister_device(data->lm75[0]);
-       i2c_unregister_device(data->lm75[1]);
 free_mem:
        kfree(data);
 exit:
index 574c160..13d9b14 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Intel(R) Trace Hub Memory Storage Unit (MSU) data structures
  *
index c0378c3..91dfeba 100644 (file)
@@ -164,6 +164,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1a6),
                .driver_data = (kernel_ulong_t)0,
        },
+       {
+               /* Lewisburg PCH */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa226),
+               .driver_data = (kernel_ulong_t)0,
+       },
        {
                /* Gemini Lake */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e),
@@ -199,6 +204,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
                .driver_data = (kernel_ulong_t)&intel_th_2x,
        },
+       {
+               /* Tiger Lake PCH */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa0a6),
+               .driver_data = (kernel_ulong_t)&intel_th_2x,
+       },
        { 0 },
 };
 
index e9381ba..7dfc043 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Intel(R) Trace Hub PTI output data structures
  *
index e55b902..181e7ff 100644 (file)
@@ -1276,7 +1276,6 @@ int stm_source_register_device(struct device *parent,
 
 err:
        put_device(&src->dev);
-       kfree(src);
 
        return err;
 }
index d7fd76b..19ef2b0 100644 (file)
@@ -790,7 +790,10 @@ static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
 
 static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
 {
-       u32 val = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       u32 val;
+
+       /* We do not support the SMBUS Quick command */
+       val = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
 
        if (adap->algo->reg_slave)
                val |= I2C_FUNC_SLAVE;
index e7f9305..f5f0017 100644 (file)
@@ -94,6 +94,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
 
        dev->disable_int(dev);
        dev->disable(dev);
+       synchronize_irq(dev->irq);
        dev->slave = NULL;
        pm_runtime_put(dev->dev);
 
index 35b302d..959d491 100644 (file)
@@ -69,6 +69,7 @@ struct em_i2c_device {
        struct completion msg_done;
        struct clk *sclk;
        struct i2c_client *slave;
+       int irq;
 };
 
 static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
@@ -339,6 +340,12 @@ static int em_i2c_unreg_slave(struct i2c_client *slave)
 
        writeb(0, priv->base + I2C_OFS_SVA0);
 
+       /*
+        * Wait for interrupt to finish. New slave irqs cannot happen because we
+        * cleared the slave address and, thus, only extension codes will be
+        * detected which do not use the slave ptr.
+        */
+       synchronize_irq(priv->irq);
        priv->slave = NULL;
 
        return 0;
@@ -355,7 +362,7 @@ static int em_i2c_probe(struct platform_device *pdev)
 {
        struct em_i2c_device *priv;
        struct resource *r;
-       int irq, ret;
+       int ret;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -390,8 +397,8 @@ static int em_i2c_probe(struct platform_device *pdev)
 
        em_i2c_reset(&priv->adap);
 
-       irq = platform_get_irq(pdev, 0);
-       ret = devm_request_irq(&pdev->dev, irq, em_i2c_irq_handler, 0,
+       priv->irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
                                "em_i2c", priv);
        if (ret)
                goto err_clk;
@@ -401,7 +408,8 @@ static int em_i2c_probe(struct platform_device *pdev)
        if (ret)
                goto err_clk;
 
-       dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, irq);
+       dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr,
+                priv->irq);
 
        return 0;
 
index f295693..2e08b47 100644 (file)
@@ -1194,19 +1194,28 @@ static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle,
        int i;
 
        status = acpi_get_object_info(obj_handle, &info);
-       if (!ACPI_SUCCESS(status) || !(info->valid & ACPI_VALID_HID))
+       if (ACPI_FAILURE(status))
                return AE_OK;
 
+       if (!(info->valid & ACPI_VALID_HID))
+               goto smo88xx_not_found;
+
        hid = info->hardware_id.string;
        if (!hid)
-               return AE_OK;
+               goto smo88xx_not_found;
 
        i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid);
        if (i < 0)
-               return AE_OK;
+               goto smo88xx_not_found;
+
+       kfree(info);
 
        *((bool *)return_value) = true;
        return AE_CTRL_TERMINATE;
+
+smo88xx_not_found:
+       kfree(info);
+       return AE_OK;
 }
 
 static bool is_dell_system_with_lis3lv02d(void)
index b1b8b93..15f6cde 100644 (file)
@@ -273,8 +273,8 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
 }
 
 /* Functions for DMA support */
-static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
-                              dma_addr_t phy_addr)
+static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
+                                               dma_addr_t phy_addr)
 {
        struct imx_i2c_dma *dma;
        struct dma_slave_config dma_sconfig;
@@ -283,7 +283,7 @@ static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
 
        dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
        if (!dma)
-               return -ENOMEM;
+               return;
 
        dma->chan_tx = dma_request_chan(dev, "tx");
        if (IS_ERR(dma->chan_tx)) {
@@ -328,7 +328,7 @@ static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
        dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
                dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
 
-       return 0;
+       return;
 
 fail_rx:
        dma_release_channel(dma->chan_rx);
@@ -336,8 +336,6 @@ fail_tx:
        dma_release_channel(dma->chan_tx);
 fail_al:
        devm_kfree(dev, dma);
-       /* return successfully if there is no dma support */
-       return ret == -ENODEV ? 0 : ret;
 }
 
 static void i2c_imx_dma_callback(void *arg)
@@ -1165,17 +1163,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
        dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
        dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
                i2c_imx->adapter.name);
+       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
 
        /* Init DMA config if supported */
-       ret = i2c_imx_dma_request(i2c_imx, phy_addr);
-       if (ret < 0)
-               goto del_adapter;
+       i2c_imx_dma_request(i2c_imx, phy_addr);
 
-       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
        return 0;   /* Return OK */
 
-del_adapter:
-       i2c_del_adapter(&i2c_imx->adapter);
 clk_notifier_unregister:
        clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
 rpm_disable:
index 252edb4..29eae1b 100644 (file)
@@ -234,6 +234,10 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
        .max_num_msgs = 255,
 };
 
+static const struct i2c_adapter_quirks mt8183_i2c_quirks = {
+       .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
 static const struct mtk_i2c_compatible mt2712_compat = {
        .regs = mt_i2c_regs_v1,
        .pmic_i2c = 0,
@@ -298,6 +302,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
 };
 
 static const struct mtk_i2c_compatible mt8183_compat = {
+       .quirks = &mt8183_i2c_quirks,
        .regs = mt_i2c_regs_v2,
        .pmic_i2c = 0,
        .dcm = 0,
@@ -870,7 +875,11 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
 
 static u32 mtk_i2c_functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       if (adap->quirks->flags & I2C_AQ_NO_ZERO_LEN)
+               return I2C_FUNC_I2C |
+                       (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+       else
+               return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
 static const struct i2c_algorithm mtk_i2c_algorithm = {
index c46c4bd..cba325e 100644 (file)
@@ -91,7 +91,7 @@
 #define SB800_PIIX4_PORT_IDX_MASK      0x06
 #define SB800_PIIX4_PORT_IDX_SHIFT     1
 
-/* On kerncz, SmBus0Sel is at bit 20:19 of PMx00 DecodeEn */
+/* On kerncz and Hudson2, SmBus0Sel is at bit 20:19 of PMx00 DecodeEn */
 #define SB800_PIIX4_PORT_IDX_KERNCZ            0x02
 #define SB800_PIIX4_PORT_IDX_MASK_KERNCZ       0x18
 #define SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ      3
@@ -358,18 +358,16 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        /* Find which register is used for port selection */
        if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD ||
            PIIX4_dev->vendor == PCI_VENDOR_ID_HYGON) {
-               switch (PIIX4_dev->device) {
-               case PCI_DEVICE_ID_AMD_KERNCZ_SMBUS:
+               if (PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS ||
+                   (PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+                    PIIX4_dev->revision >= 0x1F)) {
                        piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_KERNCZ;
                        piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK_KERNCZ;
                        piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ;
-                       break;
-               case PCI_DEVICE_ID_AMD_HUDSON2_SMBUS:
-               default:
+               } else {
                        piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_ALT;
                        piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
                        piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
-                       break;
                }
        } else {
                if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2,
index d39a460..531c011 100644 (file)
@@ -139,6 +139,7 @@ struct rcar_i2c_priv {
        enum dma_data_direction dma_direction;
 
        struct reset_control *rstc;
+       int irq;
 };
 
 #define rcar_i2c_priv_to_dev(p)                ((p)->adap.dev.parent)
@@ -861,9 +862,11 @@ static int rcar_unreg_slave(struct i2c_client *slave)
 
        WARN_ON(!priv->slave);
 
+       /* disable irqs and ensure none is running before clearing ptr */
        rcar_i2c_write(priv, ICSIER, 0);
        rcar_i2c_write(priv, ICSCR, 0);
 
+       synchronize_irq(priv->irq);
        priv->slave = NULL;
 
        pm_runtime_put(rcar_i2c_priv_to_dev(priv));
@@ -918,7 +921,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
        struct i2c_adapter *adap;
        struct device *dev = &pdev->dev;
        struct i2c_timings i2c_t;
-       int irq, ret;
+       int ret;
 
        /* Otherwise logic will break because some bytes must always use PIO */
        BUILD_BUG_ON_MSG(RCAR_MIN_DMA_LEN < 3, "Invalid min DMA length");
@@ -984,10 +987,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)
                pm_runtime_put(dev);
 
 
-       irq = platform_get_irq(pdev, 0);
-       ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv);
+       priv->irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv);
        if (ret < 0) {
-               dev_err(dev, "cannot get irq %d\n", irq);
+               dev_err(dev, "cannot get irq %d\n", priv->irq);
                goto out_pm_disable;
        }
 
index 868755f..2c21893 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * i2c-stm32.h
  *
index f26ed49..9c440fa 100644 (file)
@@ -832,7 +832,7 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
  */
 void i2c_unregister_device(struct i2c_client *client)
 {
-       if (!client)
+       if (IS_ERR_OR_NULL(client))
                return;
 
        if (client->dev.of_node) {
index 69cc040..9e2e140 100644 (file)
@@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_to_i3cdev);
 
+/**
+ * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
+ * @i3cdev: I3C device
+ * @id_table: I3C device match table
+ *
+ * Return: a pointer to an i3c_device_id object or NULL if there's no match.
+ */
+const struct i3c_device_id *
+i3c_device_match_id(struct i3c_device *i3cdev,
+                   const struct i3c_device_id *id_table)
+{
+       struct i3c_device_info devinfo;
+       const struct i3c_device_id *id;
+
+       i3c_device_get_info(i3cdev, &devinfo);
+
+       /*
+        * The lower 32bits of the provisional ID is just filled with a random
+        * value, try to match using DCR info.
+        */
+       if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
+               u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
+               u16 part = I3C_PID_PART_ID(devinfo.pid);
+               u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
+
+               /* First try to match by manufacturer/part ID. */
+               for (id = id_table; id->match_flags != 0; id++) {
+                       if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
+                           I3C_MATCH_MANUF_AND_PART)
+                               continue;
+
+                       if (manuf != id->manuf_id || part != id->part_id)
+                               continue;
+
+                       if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
+                           ext_info != id->extra_info)
+                               continue;
+
+                       return id;
+               }
+       }
+
+       /* Fallback to DCR match. */
+       for (id = id_table; id->match_flags != 0; id++) {
+               if ((id->match_flags & I3C_MATCH_DCR) &&
+                   id->dcr == devinfo.dcr)
+                       return id;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(i3c_device_match_id);
+
 /**
  * i3c_driver_register_with_owner() - register an I3C device driver
  *
index d6f8b03..5c051db 100644 (file)
@@ -123,7 +123,7 @@ static struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev)
        if (dev->type == &i3c_device_type)
                return dev_to_i3cdev(dev)->desc;
 
-       master = container_of(dev, struct i3c_master_controller, dev);
+       master = dev_to_i3cmaster(dev);
 
        return master->this;
 }
@@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = {
        .uevent = i3c_device_uevent,
 };
 
-static const struct i3c_device_id *
-i3c_device_match_id(struct i3c_device *i3cdev,
-                   const struct i3c_device_id *id_table)
-{
-       struct i3c_device_info devinfo;
-       const struct i3c_device_id *id;
-
-       i3c_device_get_info(i3cdev, &devinfo);
-
-       /*
-        * The lower 32bits of the provisional ID is just filled with a random
-        * value, try to match using DCR info.
-        */
-       if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
-               u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
-               u16 part = I3C_PID_PART_ID(devinfo.pid);
-               u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
-
-               /* First try to match by manufacturer/part ID. */
-               for (id = id_table; id->match_flags != 0; id++) {
-                       if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
-                           I3C_MATCH_MANUF_AND_PART)
-                               continue;
-
-                       if (manuf != id->manuf_id || part != id->part_id)
-                               continue;
-
-                       if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
-                           ext_info != id->extra_info)
-                               continue;
-
-                       return id;
-               }
-       }
-
-       /* Fallback to DCR match. */
-       for (id = id_table; id->match_flags != 0; id++) {
-               if ((id->match_flags & I3C_MATCH_DCR) &&
-                   id->dcr == devinfo.dcr)
-                       return id;
-       }
-
-       return NULL;
-}
-
 static int i3c_device_match(struct device *dev, struct device_driver *drv)
 {
        struct i3c_device *i3cdev;
@@ -645,6 +600,8 @@ i3c_master_alloc_i2c_dev(struct i3c_master_controller *master,
 
        dev->common.master = master;
        dev->boardinfo = boardinfo;
+       dev->addr = boardinfo->base.addr;
+       dev->lvr = boardinfo->lvr;
 
        return dev;
 }
@@ -963,8 +920,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
 
        desc = defslvs->slaves;
        i3c_bus_for_each_i2cdev(bus, i2cdev) {
-               desc->lvr = i2cdev->boardinfo->lvr;
-               desc->static_addr = i2cdev->boardinfo->base.addr << 1;
+               desc->lvr = i2cdev->lvr;
+               desc->static_addr = i2cdev->addr << 1;
                desc++;
        }
 
@@ -1084,8 +1041,10 @@ static int i3c_master_getmwl_locked(struct i3c_master_controller *master,
        if (ret)
                goto out;
 
-       if (dest.payload.len != sizeof(*mwl))
-               return -EIO;
+       if (dest.payload.len != sizeof(*mwl)) {
+               ret = -EIO;
+               goto out;
+       }
 
        info->max_write_len = be16_to_cpu(mwl->len);
 
@@ -1631,8 +1590,8 @@ static void i3c_master_detach_free_devs(struct i3c_master_controller *master)
                                 common.node) {
                i3c_master_detach_i2c_dev(i2cdev);
                i3c_bus_set_addr_slot_status(&master->bus,
-                                       i2cdev->boardinfo->base.addr,
-                                       I3C_ADDR_SLOT_FREE);
+                                            i2cdev->addr,
+                                            I3C_ADDR_SLOT_FREE);
                i3c_master_free_i2c_dev(i2cdev);
        }
 }
@@ -2093,8 +2052,10 @@ static int of_populate_i3c_bus(struct i3c_master_controller *master)
 
        for_each_available_child_of_node(i3cbus_np, node) {
                ret = of_i3c_master_add_dev(master, node);
-               if (ret)
+               if (ret) {
+                       of_node_put(node);
                        return ret;
+               }
        }
 
        /*
index 09912d7..b0ff0e1 100644 (file)
@@ -1033,12 +1033,12 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
                return -ENOMEM;
 
        data->index = pos;
-       master->addrs[pos] = dev->boardinfo->base.addr;
+       master->addrs[pos] = dev->addr;
        master->free_pos &= ~BIT(pos);
        i2c_dev_set_master_data(dev, data);
 
        writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV |
-              DEV_ADDR_TABLE_STATIC_ADDR(dev->boardinfo->base.addr),
+              DEV_ADDR_TABLE_STATIC_ADDR(dev->addr),
               master->regs +
               DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
 
index 237f24a..10db0bf 100644 (file)
@@ -903,7 +903,8 @@ static void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev)
 static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
                                       u8 dyn_addr)
 {
-       u32 activedevs, rr;
+       unsigned long activedevs;
+       u32 rr;
        int i;
 
        if (!dyn_addr) {
@@ -913,13 +914,10 @@ static int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master,
                return ffs(master->free_rr_slots) - 1;
        }
 
-       activedevs = readl(master->regs + DEVS_CTRL) &
-                    DEVS_CTRL_DEVS_ACTIVE_MASK;
-
-       for (i = 1; i <= master->maxdevs; i++) {
-               if (!(BIT(i) & activedevs))
-                       continue;
+       activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
+       activedevs &= ~BIT(0);
 
+       for_each_set_bit(i, &activedevs, master->maxdevs + 1) {
                rr = readl(master->regs + DEV_ID_RR0(i));
                if (!(rr & DEV_ID_RR0_IS_I3C) ||
                    DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr)
@@ -1005,9 +1003,9 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
        master->free_rr_slots &= ~BIT(slot);
        i2c_dev_set_master_data(dev, data);
 
-       writel(prepare_rr0_dev_address(dev->boardinfo->base.addr),
+       writel(prepare_rr0_dev_address(dev->addr),
               master->regs + DEV_ID_RR0(data->id));
-       writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id));
+       writel(dev->lvr, master->regs + DEV_ID_RR2(data->id));
        writel(readl(master->regs + DEVS_CTRL) |
               DEVS_CTRL_DEV_ACTIVE(data->id),
               master->regs + DEVS_CTRL);
@@ -1126,18 +1124,16 @@ static void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master)
 static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
 {
        struct cdns_i3c_master *master = to_cdns_i3c_master(m);
-       u32 olddevs, newdevs;
+       unsigned long olddevs, newdevs;
        int ret, slot;
        u8 addrs[MAX_DEVS] = { };
        u8 last_addr = 0;
 
        olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
+       olddevs |= BIT(0);
 
        /* Prepare RR slots before launching DAA. */
-       for (slot = 1; slot <= master->maxdevs; slot++) {
-               if (olddevs & BIT(slot))
-                       continue;
-
+       for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) {
                ret = i3c_master_get_free_addr(m, last_addr + 1);
                if (ret < 0)
                        return -ENOSPC;
@@ -1161,10 +1157,8 @@ static int cdns_i3c_master_do_daa(struct i3c_master_controller *m)
         * Clear all retaining registers filled during DAA. We already
         * have the addressed assigned to them in the addrs array.
         */
-       for (slot = 1; slot <= master->maxdevs; slot++) {
-               if (newdevs & BIT(slot))
-                       i3c_master_add_i3c_dev_locked(m, addrs[slot]);
-       }
+       for_each_set_bit(slot, &newdevs, master->maxdevs + 1)
+               i3c_master_add_i3c_dev_locked(m, addrs[slot]);
 
        /*
         * Clear slots that ended up not being used. Can be caused by I3C
index 9eada39..1c227ea 100644 (file)
@@ -567,15 +567,6 @@ config BLK_DEV_SVWKS
          This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
          chipsets.
 
-config BLK_DEV_SGIIOC4
-       tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
-       depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
-         chipset, which has one channel and can support two devices.
-         Please say Y here if you have an Altix System from SGI.
-
 config BLK_DEV_SIIMAGE
        tristate "Silicon Image chipset support"
        select BLK_DEV_IDEDMA_PCI
index 9f617a7..cac02db 100644 (file)
@@ -59,7 +59,6 @@ obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)    += pdc202xx_new.o
 obj-$(CONFIG_BLK_DEV_PIIX)             += piix.o
 obj-$(CONFIG_BLK_DEV_RZ1000)           += rz1000.o
 obj-$(CONFIG_BLK_DEV_SVWKS)            += serverworks.o
-obj-$(CONFIG_BLK_DEV_SGIIOC4)          += sgiioc4.o
 obj-$(CONFIG_BLK_DEV_SIIMAGE)          += siimage.o
 obj-$(CONFIG_BLK_DEV_SIS5513)          += sis5513.o
 obj-$(CONFIG_BLK_DEV_SL82C105)         += sl82c105.o
diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c
deleted file mode 100644 (file)
index 2d35e9f..0000000
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * Copyright (c) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
- * Copyright (C) 2008-2009 MontaVista Software, Inc.
- *
- * 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 would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/scatterlist.h>
-#include <linux/ioc4.h>
-#include <linux/io.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "SGIIOC4"
-
-/* IOC4 Specific Definitions */
-#define IOC4_CMD_OFFSET                0x100
-#define IOC4_CTRL_OFFSET       0x120
-#define IOC4_DMA_OFFSET                0x140
-#define IOC4_INTR_OFFSET       0x0
-
-#define IOC4_TIMING            0x00
-#define IOC4_DMA_PTR_L         0x01
-#define IOC4_DMA_PTR_H         0x02
-#define IOC4_DMA_ADDR_L                0x03
-#define IOC4_DMA_ADDR_H                0x04
-#define IOC4_BC_DEV            0x05
-#define IOC4_BC_MEM            0x06
-#define        IOC4_DMA_CTRL           0x07
-#define        IOC4_DMA_END_ADDR       0x08
-
-/* Bits in the IOC4 Control/Status Register */
-#define        IOC4_S_DMA_START        0x01
-#define        IOC4_S_DMA_STOP         0x02
-#define        IOC4_S_DMA_DIR          0x04
-#define        IOC4_S_DMA_ACTIVE       0x08
-#define        IOC4_S_DMA_ERROR        0x10
-#define        IOC4_ATA_MEMERR         0x02
-
-/* Read/Write Directions */
-#define        IOC4_DMA_WRITE          0x04
-#define        IOC4_DMA_READ           0x00
-
-/* Interrupt Register Offsets */
-#define IOC4_INTR_REG          0x03
-#define        IOC4_INTR_SET           0x05
-#define        IOC4_INTR_CLEAR         0x07
-
-#define IOC4_IDE_CACHELINE_SIZE        128
-#define IOC4_CMD_CTL_BLK_SIZE  0x20
-#define IOC4_SUPPORTED_FIRMWARE_REV 46
-
-struct ioc4_dma_regs {
-       u32 timing_reg0;
-       u32 timing_reg1;
-       u32 low_mem_ptr;
-       u32 high_mem_ptr;
-       u32 low_mem_addr;
-       u32 high_mem_addr;
-       u32 dev_byte_count;
-       u32 mem_byte_count;
-       u32 status;
-};
-
-/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */
-/* IOC4 has only 1 IDE channel */
-#define IOC4_PRD_BYTES         16
-#define IOC4_PRD_ENTRIES       (PAGE_SIZE / (4 * IOC4_PRD_BYTES))
-
-
-static void sgiioc4_init_hwif_ports(struct ide_hw *hw,
-                                   unsigned long data_port,
-                                   unsigned long ctrl_port,
-                                   unsigned long irq_port)
-{
-       unsigned long reg = data_port;
-       int i;
-
-       /* Registers are word (32 bit) aligned */
-       for (i = 0; i <= 7; i++)
-               hw->io_ports_array[i] = reg + i * 4;
-
-       hw->io_ports.ctl_addr = ctrl_port;
-       hw->io_ports.irq_addr = irq_port;
-}
-
-static int sgiioc4_checkirq(ide_hwif_t *hwif)
-{
-       unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4;
-
-       if (readl((void __iomem *)intr_addr) & 0x03)
-               return 1;
-
-       return 0;
-}
-
-static u8 sgiioc4_read_status(ide_hwif_t *);
-
-static int sgiioc4_clearirq(ide_drive_t *drive)
-{
-       u32 intr_reg;
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2);
-
-       /* Code to check for PCI error conditions */
-       intr_reg = readl((void __iomem *)other_ir);
-       if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */
-               /*
-                * Using sgiioc4_read_status to read the Status register has a
-                * side effect of clearing the interrupt.  The first read should
-                * clear it if it is set.  The second read should return
-                * a "clear" status if it got cleared.  If not, then spin
-                * for a bit trying to clear it.
-                */
-               u8 stat = sgiioc4_read_status(hwif);
-               int count = 0;
-
-               stat = sgiioc4_read_status(hwif);
-               while ((stat & ATA_BUSY) && (count++ < 100)) {
-                       udelay(1);
-                       stat = sgiioc4_read_status(hwif);
-               }
-
-               if (intr_reg & 0x02) {
-                       struct pci_dev *dev = to_pci_dev(hwif->dev);
-                       /* Error when transferring DMA data on PCI bus */
-                       u32 pci_err_addr_low, pci_err_addr_high,
-                           pci_stat_cmd_reg;
-
-                       pci_err_addr_low =
-                               readl((void __iomem *)io_ports->irq_addr);
-                       pci_err_addr_high =
-                               readl((void __iomem *)(io_ports->irq_addr + 4));
-                       pci_read_config_dword(dev, PCI_COMMAND,
-                                             &pci_stat_cmd_reg);
-                       printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: "
-                              "status-cmd reg is 0x%x\n",
-                              __func__, drive->name, pci_stat_cmd_reg);
-                       printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n",
-                              __func__, drive->name,
-                              pci_err_addr_high, pci_err_addr_low);
-                       /* Clear the PCI Error indicator */
-                       pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
-               }
-
-               /* Clear the Interrupt, Error bits on the IOC4 */
-               writel(0x03, (void __iomem *)other_ir);
-
-               intr_reg = readl((void __iomem *)other_ir);
-       }
-
-       return intr_reg & 3;
-}
-
-static void sgiioc4_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4;
-       unsigned int reg = readl((void __iomem *)ioc4_dma_addr);
-       unsigned int temp_reg = reg | IOC4_S_DMA_START;
-
-       writel(temp_reg, (void __iomem *)ioc4_dma_addr);
-}
-
-static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
-{
-       unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
-       u32     ioc4_dma;
-       int     count;
-
-       count = 0;
-       ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
-       while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) {
-               udelay(1);
-               ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
-       }
-       return ioc4_dma;
-}
-
-/* Stops the IOC4 DMA Engine */
-static int sgiioc4_dma_end(ide_drive_t *drive)
-{
-       u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long dma_base = hwif->dma_base;
-       int dma_stat = 0;
-       unsigned long *ending_dma = ide_get_hwifdata(hwif);
-
-       writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4));
-
-       ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
-       if (ioc4_dma & IOC4_S_DMA_STOP) {
-               printk(KERN_ERR
-                      "%s(%s): IOC4 DMA STOP bit is still 1 :"
-                      "ioc4_dma_reg 0x%x\n",
-                      __func__, drive->name, ioc4_dma);
-               dma_stat = 1;
-       }
-
-       /*
-        * The IOC4 will DMA 1's to the ending DMA area to indicate that
-        * previous data DMA is complete.  This is necessary because of relaxed
-        * ordering between register reads and DMA writes on the Altix.
-        */
-       while ((cnt++ < 200) && (!valid)) {
-               for (num = 0; num < 16; num++) {
-                       if (ending_dma[num]) {
-                               valid = 1;
-                               break;
-                       }
-               }
-               udelay(1);
-       }
-       if (!valid) {
-               printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__,
-                      drive->name);
-               dma_stat = 1;
-       }
-
-       bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4));
-       bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4));
-
-       if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
-               if (bc_dev > bc_mem + 8) {
-                       printk(KERN_ERR
-                              "%s(%s): WARNING!! byte_count_dev %d "
-                              "!= byte_count_mem %d\n",
-                              __func__, drive->name, bc_dev, bc_mem);
-               }
-       }
-
-       return dma_stat;
-}
-
-static void sgiioc4_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-/* Returns 1 if DMA IRQ issued, 0 otherwise */
-static int sgiioc4_dma_test_irq(ide_drive_t *drive)
-{
-       return sgiioc4_checkirq(drive->hwif);
-}
-
-static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
-{
-       if (!on)
-               sgiioc4_clearirq(drive);
-}
-
-static void sgiioc4_resetproc(ide_drive_t *drive)
-{
-       struct ide_cmd *cmd = &drive->hwif->cmd;
-
-       sgiioc4_dma_end(drive);
-       ide_dma_unmap_sg(drive, cmd);
-       sgiioc4_clearirq(drive);
-}
-
-static void sgiioc4_dma_lost_irq(ide_drive_t *drive)
-{
-       sgiioc4_resetproc(drive);
-
-       ide_dma_lost_irq(drive);
-}
-
-static u8 sgiioc4_read_status(ide_hwif_t *hwif)
-{
-       unsigned long port = hwif->io_ports.status_addr;
-       u8 reg = (u8) readb((void __iomem *) port);
-
-       if (!(reg & ATA_BUSY)) {        /* Not busy... check for interrupt */
-               unsigned long other_ir = port - 0x110;
-               unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
-
-               /* Clear the Interrupt, Error bits on the IOC4 */
-               if (intr_reg & 0x03) {
-                       writel(0x03, (void __iomem *) other_ir);
-                       intr_reg = (u32) readl((void __iomem *) other_ir);
-               }
-       }
-
-       return reg;
-}
-
-/* Creates a DMA map for the scatter-gather list entries */
-static int ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
-       int num_ports = sizeof(struct ioc4_dma_regs);
-       void *pad;
-
-       printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
-
-       if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
-               printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx "
-                      "already in use\n", __func__, hwif->name,
-                      dma_base, dma_base + num_ports - 1);
-               return -1;
-       }
-
-       hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr +
-                        IOC4_DMA_OFFSET;
-
-       hwif->sg_max_nents = IOC4_PRD_ENTRIES;
-
-       hwif->prd_max_nents = IOC4_PRD_ENTRIES;
-       hwif->prd_ent_size = IOC4_PRD_BYTES;
-
-       if (ide_allocate_dma_engine(hwif))
-               goto dma_pci_alloc_failure;
-
-       pad = dma_alloc_coherent(&dev->dev, IOC4_IDE_CACHELINE_SIZE,
-                                  (dma_addr_t *)&hwif->extra_base, GFP_KERNEL);
-       if (pad) {
-               ide_set_hwifdata(hwif, pad);
-               return 0;
-       }
-
-       ide_release_dma_engine(hwif);
-
-       printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n",
-              __func__, hwif->name);
-       printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
-
-dma_pci_alloc_failure:
-       release_mem_region(dma_base, num_ports);
-
-       return -1;
-}
-
-/* Initializes the IOC4 DMA Engine */
-static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive)
-{
-       u32 ioc4_dma;
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long dma_base = hwif->dma_base;
-       unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
-       u32 dma_addr, ending_dma_addr;
-
-       ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
-
-       if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
-               printk(KERN_WARNING "%s(%s): Warning!! DMA from previous "
-                      "transfer was still active\n", __func__, drive->name);
-               writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
-               ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
-               if (ioc4_dma & IOC4_S_DMA_STOP)
-                       printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is "
-                              "still 1\n", __func__, drive->name);
-       }
-
-       ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
-       if (ioc4_dma & IOC4_S_DMA_ERROR) {
-               printk(KERN_WARNING "%s(%s): Warning!! DMA Error during "
-                      "previous transfer, status 0x%x\n",
-                      __func__, drive->name, ioc4_dma);
-               writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
-               ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
-               if (ioc4_dma & IOC4_S_DMA_STOP)
-                       printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is "
-                              "still 1\n", __func__, drive->name);
-       }
-
-       /* Address of the Scatter Gather List */
-       dma_addr = cpu_to_le32(hwif->dmatable_dma);
-       writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4));
-
-       /* Address of the Ending DMA */
-       memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
-       ending_dma_addr = cpu_to_le32(hwif->extra_base);
-       writel(ending_dma_addr, (void __iomem *)(dma_base +
-                                                IOC4_DMA_END_ADDR * 4));
-
-       writel(dma_direction, (void __iomem *)ioc4_dma_addr);
-}
-
-/* IOC4 Scatter Gather list Format                                      */
-/* 128 Bit entries to support 64 bit addresses in the future            */
-/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format     */
-/* --------------------------------------------------------------------- */
-/* | Upper 32 bits - Zero          |           Lower 32 bits- address | */
-/* --------------------------------------------------------------------- */
-/* | Upper 32 bits - Zero          |EOL| 15 unused     | 16 Bit Length| */
-/* --------------------------------------------------------------------- */
-/* Creates the scatter gather list, DMA Table                           */
-
-static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned int *table = hwif->dmatable_cpu;
-       unsigned int count = 0, i = cmd->sg_nents;
-       struct scatterlist *sg = hwif->sg_table;
-
-       while (i && sg_dma_len(sg)) {
-               dma_addr_t cur_addr;
-               int cur_len;
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               while (cur_len) {
-                       if (count++ >= IOC4_PRD_ENTRIES) {
-                               printk(KERN_WARNING
-                                      "%s: DMA table too small\n",
-                                      drive->name);
-                               return 0;
-                       } else {
-                               u32 bcount =
-                                   0x10000 - (cur_addr & 0xffff);
-
-                               if (bcount > cur_len)
-                                       bcount = cur_len;
-
-                               /*
-                                * Put the address, length in
-                                * the IOC4 dma-table format
-                                */
-                               *table = 0x0;
-                               table++;
-                               *table = cpu_to_be32(cur_addr);
-                               table++;
-                               *table = 0x0;
-                               table++;
-
-                               *table = cpu_to_be32(bcount);
-                               table++;
-
-                               cur_addr += bcount;
-                               cur_len -= bcount;
-                       }
-               }
-
-               sg = sg_next(sg);
-               i--;
-       }
-
-       if (count) {
-               table--;
-               *table |= cpu_to_be32(0x80000000);
-               return count;
-       }
-
-       return 0;               /* revert to PIO for this request */
-}
-
-static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       int ddir;
-       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
-       if (sgiioc4_build_dmatable(drive, cmd) == 0)
-               /* try PIO instead of DMA */
-               return 1;
-
-       if (write)
-               /* Writes TO the IOC4 FROM Main Memory */
-               ddir = IOC4_DMA_READ;
-       else
-               /* Writes FROM the IOC4 TO Main Memory */
-               ddir = IOC4_DMA_WRITE;
-
-       sgiioc4_configure_for_dma(ddir, drive);
-
-       return 0;
-}
-
-static const struct ide_tp_ops sgiioc4_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = sgiioc4_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ide_dev_select,
-       .tf_load                = ide_tf_load,
-       .tf_read                = ide_tf_read,
-
-       .input_data             = ide_input_data,
-       .output_data            = ide_output_data,
-};
-
-static const struct ide_port_ops sgiioc4_port_ops = {
-       .set_dma_mode           = sgiioc4_set_dma_mode,
-       /* reset DMA engine, clear IRQs */
-       .resetproc              = sgiioc4_resetproc,
-};
-
-static const struct ide_dma_ops sgiioc4_dma_ops = {
-       .dma_host_set           = sgiioc4_dma_host_set,
-       .dma_setup              = sgiioc4_dma_setup,
-       .dma_start              = sgiioc4_dma_start,
-       .dma_end                = sgiioc4_dma_end,
-       .dma_test_irq           = sgiioc4_dma_test_irq,
-       .dma_lost_irq           = sgiioc4_dma_lost_irq,
-};
-
-static const struct ide_port_info sgiioc4_port_info = {
-       .name                   = DRV_NAME,
-       .chipset                = ide_pci,
-       .init_dma               = ide_dma_sgiioc4,
-       .tp_ops                 = &sgiioc4_tp_ops,
-       .port_ops               = &sgiioc4_port_ops,
-       .dma_ops                = &sgiioc4_dma_ops,
-       .host_flags             = IDE_HFLAG_MMIO,
-       .irq_flags              = IRQF_SHARED,
-       .mwdma_mask             = ATA_MWDMA2_ONLY,
-};
-
-static int sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
-{
-       unsigned long cmd_base, irqport;
-       unsigned long bar0, cmd_phys_base, ctl;
-       void __iomem *virt_base;
-       struct ide_hw hw, *hws[] = { &hw };
-       int rc;
-
-       /* Get the CmdBlk and CtrlBlk base registers */
-       bar0 = pci_resource_start(dev, 0);
-       virt_base = pci_ioremap_bar(dev, 0);
-       if (virt_base == NULL) {
-               printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
-                               DRV_NAME, bar0);
-               return -ENOMEM;
-       }
-       cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET;
-       ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET;
-       irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET;
-
-       cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
-       if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
-                              DRV_NAME) == NULL) {
-               printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx "
-                      "already in use\n", DRV_NAME, pci_name(dev),
-                      cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
-               rc = -EBUSY;
-               goto req_mem_rgn_err;
-       }
-
-       /* Initialize the IO registers */
-       memset(&hw, 0, sizeof(hw));
-       sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
-       hw.irq = dev->irq;
-       hw.dev = &dev->dev;
-
-       /* Initialize chipset IRQ registers */
-       writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
-
-       rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL);
-       if (!rc)
-               return 0;
-
-       release_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE);
-req_mem_rgn_err:
-       iounmap(virt_base);
-       return rc;
-}
-
-static unsigned int pci_init_sgiioc4(struct pci_dev *dev)
-{
-       int ret;
-
-       printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
-                        DRV_NAME, pci_name(dev), dev->revision);
-
-       if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) {
-               printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
-                               "firmware is obsolete - please upgrade to "
-                               "revision46 or higher\n",
-                               DRV_NAME, pci_name(dev));
-               ret = -EAGAIN;
-               goto out;
-       }
-       ret = sgiioc4_ide_setup_pci_device(dev);
-out:
-       return ret;
-}
-
-static int ioc4_ide_attach_one(struct ioc4_driver_data *idd)
-{
-       /*
-        * PCI-RT does not bring out IDE connection.
-        * Do not attach to this particular IOC4.
-        */
-       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
-               return 0;
-
-       return pci_init_sgiioc4(idd->idd_pdev);
-}
-
-static struct ioc4_submodule ioc4_ide_submodule = {
-       .is_name = "IOC4_ide",
-       .is_owner = THIS_MODULE,
-       .is_probe = ioc4_ide_attach_one,
-};
-
-static int __init ioc4_ide_init(void)
-{
-       return ioc4_register_submodule(&ioc4_ide_submodule);
-}
-
-late_initcall(ioc4_ide_init); /* Call only after IDE init is done */
-
-MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
-MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
index 7e32862..f0af3a4 100644 (file)
@@ -958,7 +958,7 @@ config TI_ADC161S626
 
 config TI_ADS1015
        tristate "Texas Instruments ADS1015 ADC"
-       depends on I2C && !SENSORS_ADS1015
+       depends on I2C
        select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
index 0e3c652..da073d7 100644 (file)
@@ -480,7 +480,7 @@ static int max9611_init(struct max9611_dev *max9611)
        if (ret)
                return ret;
 
-       regval = ret & MAX9611_TEMP_MASK;
+       regval &= MAX9611_TEMP_MASK;
 
        if ((regval > MAX9611_TEMP_MAX_POS &&
             regval < MAX9611_TEMP_MIN_NEG) ||
index e48f15c..ff82863 100644 (file)
@@ -276,11 +276,11 @@ static int adf4371_set_freq(struct adf4371_state *st, unsigned long long freq,
        st->buf[0] = st->integer >> 8;
        st->buf[1] = 0x40; /* REG12 default */
        st->buf[2] = 0x00;
-       st->buf[3] = st->fract2 & 0xFF;
-       st->buf[4] = st->fract2 >> 7;
-       st->buf[5] = st->fract2 >> 15;
+       st->buf[3] = st->fract1 & 0xFF;
+       st->buf[4] = st->fract1 >> 8;
+       st->buf[5] = st->fract1 >> 16;
        st->buf[6] = ADF4371_FRAC2WORD_L(st->fract2 & 0x7F) |
-                    ADF4371_FRAC1WORD(st->fract1 >> 23);
+                    ADF4371_FRAC1WORD(st->fract1 >> 24);
        st->buf[7] = ADF4371_FRAC2WORD_H(st->fract2 >> 7);
        st->buf[8] = st->mod2 & 0xFF;
        st->buf[9] = ADF4371_MOD2WORD(st->mod2 >> 8);
index 19f1730..a68d0cc 100644 (file)
@@ -4724,10 +4724,14 @@ static int __init cma_init(void)
        if (ret)
                goto err;
 
-       cma_configfs_init();
+       ret = cma_configfs_init();
+       if (ret)
+               goto err_ib;
 
        return 0;
 
+err_ib:
+       ib_unregister_client(&cma_client);
 err:
        unregister_netdevice_notifier(&cma_nb);
        ib_sa_unregister_client(&sa_client);
index 45d5164..af8c85d 100644 (file)
@@ -38,6 +38,9 @@ int rdma_counter_set_auto_mode(struct ib_device *dev, u8 port,
        int ret;
 
        port_counter = &dev->port_data[port].port_counter;
+       if (!port_counter->hstats)
+               return -EOPNOTSUPP;
+
        mutex_lock(&port_counter->lock);
        if (on) {
                ret = __counter_set_mode(&port_counter->mode,
@@ -146,13 +149,11 @@ static bool auto_mode_match(struct ib_qp *qp, struct rdma_counter *counter,
        struct auto_mode_param *param = &counter->mode.param;
        bool match = true;
 
-       if (rdma_is_kernel_res(&counter->res) != rdma_is_kernel_res(&qp->res))
+       if (!rdma_is_visible_in_pid_ns(&qp->res))
                return false;
 
-       /* Ensure that counter belong to right PID */
-       if (!rdma_is_kernel_res(&counter->res) &&
-           !rdma_is_kernel_res(&qp->res) &&
-           (task_pid_vnr(counter->res.task) != current->pid))
+       /* Ensure that counter belongs to the right PID */
+       if (task_pid_nr(counter->res.task) != task_pid_nr(qp->res.task))
                return false;
 
        if (auto_mask & RDMA_COUNTER_MASK_QP_TYPE)
@@ -421,7 +422,7 @@ static struct ib_qp *rdma_counter_get_qp(struct ib_device *dev, u32 qp_num)
        return qp;
 
 err:
-       rdma_restrack_put(&qp->res);
+       rdma_restrack_put(res);
        return NULL;
 }
 
@@ -509,6 +510,9 @@ int rdma_counter_bind_qpn_alloc(struct ib_device *dev, u8 port,
        if (!rdma_is_port_valid(dev, port))
                return -EINVAL;
 
+       if (!dev->port_data[port].port_counter.hstats)
+               return -EOPNOTSUPP;
+
        qp = rdma_counter_get_qp(dev, qp_num);
        if (!qp)
                return -ENOENT;
index 783e465..020c269 100644 (file)
@@ -382,8 +382,7 @@ static int fill_res_info(struct sk_buff *msg, struct ib_device *device)
        for (i = 0; i < RDMA_RESTRACK_MAX; i++) {
                if (!names[i])
                        continue;
-               curr = rdma_restrack_count(device, i,
-                                          task_active_pid_ns(current));
+               curr = rdma_restrack_count(device, i);
                ret = fill_res_info_entry(msg, names[i], curr);
                if (ret)
                        goto err;
@@ -1952,12 +1951,16 @@ static int stat_get_doit_qp(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        if (fill_nldev_handle(msg, device) ||
            nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) ||
-           nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, mode))
+           nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, mode)) {
+               ret = -EMSGSIZE;
                goto err_msg;
+       }
 
        if ((mode == RDMA_COUNTER_MODE_AUTO) &&
-           nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask))
+           nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask)) {
+               ret = -EMSGSIZE;
                goto err_msg;
+       }
 
        nlmsg_end(msg, nlh);
        ib_device_put(device);
index bddff42..a07665f 100644 (file)
@@ -107,10 +107,8 @@ void rdma_restrack_clean(struct ib_device *dev)
  * rdma_restrack_count() - the current usage of specific object
  * @dev:  IB device
  * @type: actual type of object to operate
- * @ns:   PID namespace
  */
-int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
-                       struct pid_namespace *ns)
+int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type)
 {
        struct rdma_restrack_root *rt = &dev->res[type];
        struct rdma_restrack_entry *e;
@@ -119,10 +117,9 @@ int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
 
        xa_lock(&rt->xa);
        xas_for_each(&xas, e, U32_MAX) {
-               if (ns == &init_pid_ns ||
-                   (!rdma_is_kernel_res(e) &&
-                    ns == task_active_pid_ns(e->task)))
-                       cnt++;
+               if (!rdma_is_visible_in_pid_ns(e))
+                       continue;
+               cnt++;
        }
        xa_unlock(&rt->xa);
        return cnt;
@@ -360,5 +357,7 @@ bool rdma_is_visible_in_pid_ns(struct rdma_restrack_entry *res)
         */
        if (rdma_is_kernel_res(res))
                return task_active_pid_ns(current) == &init_pid_ns;
-       return task_active_pid_ns(current) == task_active_pid_ns(res->task);
+
+       /* PID 0 means that resource is not found in current namespace */
+       return task_pid_vnr(res->task);
 }
index 08da840..5655366 100644 (file)
@@ -379,14 +379,9 @@ EXPORT_SYMBOL(ib_umem_release);
 
 int ib_umem_page_count(struct ib_umem *umem)
 {
-       int i;
-       int n;
+       int i, n = 0;
        struct scatterlist *sg;
 
-       if (umem->is_odp)
-               return ib_umem_num_pages(umem);
-
-       n = 0;
        for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
                n += sg_dma_len(sg) >> PAGE_SHIFT;
 
index 2a75c6f..c0e15db 100644 (file)
@@ -112,10 +112,6 @@ static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp,
         * prevent any further fault handling on this MR.
         */
        ib_umem_notifier_start_account(umem_odp);
-       umem_odp->dying = 1;
-       /* Make sure that the fact the umem is dying is out before we release
-        * all pending page faults. */
-       smp_wmb();
        complete_all(&umem_odp->notifier_completion);
        umem_odp->umem.context->invalidate_range(
                umem_odp, ib_umem_start(umem_odp), ib_umem_end(umem_odp));
index 48b04d2..60c8f76 100644 (file)
@@ -136,6 +136,13 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
                spin_unlock_irqrestore(&cmdq->lock, flags);
                return -EBUSY;
        }
+
+       size = req->cmd_size;
+       /* change the cmd_size to the number of 16byte cmdq unit.
+        * req->cmd_size is modified here
+        */
+       bnxt_qplib_set_cmd_slots(req);
+
        memset(resp, 0, sizeof(*resp));
        crsqe->resp = (struct creq_qp_event *)resp;
        crsqe->resp->cookie = req->cookie;
@@ -150,7 +157,6 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
 
        cmdq_ptr = (struct bnxt_qplib_cmdqe **)cmdq->pbl_ptr;
        preq = (u8 *)req;
-       size = req->cmd_size * BNXT_QPLIB_CMDQE_UNITS;
        do {
                /* Locate the next cmdq slot */
                sw_prod = HWQ_CMP(cmdq->prod, cmdq);
index 2138533..dfeadc1 100644 (file)
@@ -55,9 +55,7 @@
        do {                                                            \
                memset(&(req), 0, sizeof((req)));                       \
                (req).opcode = CMDQ_BASE_OPCODE_##CMD;                  \
-               (req).cmd_size = (sizeof((req)) +                       \
-                               BNXT_QPLIB_CMDQE_UNITS - 1) /           \
-                               BNXT_QPLIB_CMDQE_UNITS;                 \
+               (req).cmd_size = sizeof((req));                         \
                (req).flags = cpu_to_le16(cmd_flags);                   \
        } while (0)
 
@@ -95,6 +93,13 @@ static inline u32 bnxt_qplib_cmdqe_cnt_per_pg(u32 depth)
                 BNXT_QPLIB_CMDQE_UNITS);
 }
 
+/* Set the cmd_size to a factor of CMDQE unit */
+static inline void bnxt_qplib_set_cmd_slots(struct cmdq_base *req)
+{
+       req->cmd_size = (req->cmd_size + BNXT_QPLIB_CMDQE_UNITS - 1) /
+                        BNXT_QPLIB_CMDQE_UNITS;
+}
+
 #define MAX_CMDQ_IDX(depth)            ((depth) - 1)
 
 static inline u32 bnxt_qplib_max_cmdq_idx_per_pg(u32 depth)
index 93613e5..986c121 100644 (file)
@@ -141,12 +141,14 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
        if (!data)
                return -ENOMEM;
        copy = min(len, datalen - 1);
-       if (copy_from_user(data, buf, copy))
-               return -EFAULT;
+       if (copy_from_user(data, buf, copy)) {
+               ret = -EFAULT;
+               goto free_data;
+       }
 
        ret = debugfs_file_get(file->f_path.dentry);
        if (unlikely(ret))
-               return ret;
+               goto free_data;
        ptr = data;
        token = ptr;
        for (ptr = data; *ptr; ptr = end + 1, token = ptr) {
@@ -195,6 +197,7 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
        ret = len;
 
        debugfs_file_put(file->f_path.dentry);
+free_data:
        kfree(data);
        return ret;
 }
@@ -214,7 +217,7 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf,
                return -ENOMEM;
        ret = debugfs_file_get(file->f_path.dentry);
        if (unlikely(ret))
-               return ret;
+               goto free_data;
        bit = find_first_bit(fault->opcodes, bitsize);
        while (bit < bitsize) {
                zero = find_next_zero_bit(fault->opcodes, bitsize, bit);
@@ -232,6 +235,7 @@ static ssize_t fault_opcodes_read(struct file *file, char __user *buf,
        data[size - 1] = '\n';
        data[size] = '\0';
        ret = simple_read_from_buffer(buf, len, pos, data, size);
+free_data:
        kfree(data);
        return ret;
 }
index 996fc29..6141f4e 100644 (file)
@@ -2574,18 +2574,9 @@ void hfi1_kern_read_tid_flow_free(struct rvt_qp *qp)
        hfi1_kern_clear_hw_flow(priv->rcd, qp);
 }
 
-static bool tid_rdma_tid_err(struct hfi1_ctxtdata *rcd,
-                            struct hfi1_packet *packet, u8 rcv_type,
-                            u8 opcode)
+static bool tid_rdma_tid_err(struct hfi1_packet *packet, u8 rcv_type)
 {
        struct rvt_qp *qp = packet->qp;
-       struct hfi1_qp_priv *qpriv = qp->priv;
-       u32 ipsn;
-       struct ib_other_headers *ohdr = packet->ohdr;
-       struct rvt_ack_entry *e;
-       struct tid_rdma_request *req;
-       struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
-       u32 i;
 
        if (rcv_type >= RHF_RCV_TYPE_IB)
                goto done;
@@ -2602,41 +2593,9 @@ static bool tid_rdma_tid_err(struct hfi1_ctxtdata *rcd,
        if (rcv_type == RHF_RCV_TYPE_EAGER) {
                hfi1_restart_rc(qp, qp->s_last_psn + 1, 1);
                hfi1_schedule_send(qp);
-               goto done_unlock;
-       }
-
-       /*
-        * For TID READ response, error out QP after freeing the tid
-        * resources.
-        */
-       if (opcode == TID_OP(READ_RESP)) {
-               ipsn = mask_psn(be32_to_cpu(ohdr->u.tid_rdma.r_rsp.verbs_psn));
-               if (cmp_psn(ipsn, qp->s_last_psn) > 0 &&
-                   cmp_psn(ipsn, qp->s_psn) < 0) {
-                       hfi1_kern_read_tid_flow_free(qp);
-                       spin_unlock(&qp->s_lock);
-                       rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
-                       goto done;
-               }
-               goto done_unlock;
-       }
-
-       /*
-        * Error out the qp for TID RDMA WRITE
-        */
-       hfi1_kern_clear_hw_flow(qpriv->rcd, qp);
-       for (i = 0; i < rvt_max_atomic(rdi); i++) {
-               e = &qp->s_ack_queue[i];
-               if (e->opcode == TID_OP(WRITE_REQ)) {
-                       req = ack_to_tid_req(e);
-                       hfi1_kern_exp_rcv_clear_all(req);
-               }
        }
-       spin_unlock(&qp->s_lock);
-       rvt_rc_error(qp, IB_WC_LOC_LEN_ERR);
-       goto done;
 
-done_unlock:
+       /* Since no payload is delivered, just drop the packet */
        spin_unlock(&qp->s_lock);
 done:
        return true;
@@ -2687,12 +2646,12 @@ static bool handle_read_kdeth_eflags(struct hfi1_ctxtdata *rcd,
        u32 fpsn;
 
        lockdep_assert_held(&qp->r_lock);
+       spin_lock(&qp->s_lock);
        /* If the psn is out of valid range, drop the packet */
        if (cmp_psn(ibpsn, qp->s_last_psn) < 0 ||
            cmp_psn(ibpsn, qp->s_psn) > 0)
-               return ret;
+               goto s_unlock;
 
-       spin_lock(&qp->s_lock);
        /*
         * Note that NAKs implicitly ACK outstanding SEND and RDMA write
         * requests and implicitly NAK RDMA read and atomic requests issued
@@ -2740,9 +2699,12 @@ static bool handle_read_kdeth_eflags(struct hfi1_ctxtdata *rcd,
 
                wqe = do_rc_completion(qp, wqe, ibp);
                if (qp->s_acked == qp->s_tail)
-                       break;
+                       goto s_unlock;
        }
 
+       if (qp->s_acked == qp->s_tail)
+               goto s_unlock;
+
        /* Handle the eflags for the request */
        if (wqe->wr.opcode != IB_WR_TID_RDMA_READ)
                goto s_unlock;
@@ -2922,7 +2884,7 @@ bool hfi1_handle_kdeth_eflags(struct hfi1_ctxtdata *rcd,
                if (lnh == HFI1_LRH_GRH)
                        goto r_unlock;
 
-               if (tid_rdma_tid_err(rcd, packet, rcv_type, opcode))
+               if (tid_rdma_tid_err(packet, rcv_type))
                        goto r_unlock;
        }
 
@@ -2942,8 +2904,15 @@ bool hfi1_handle_kdeth_eflags(struct hfi1_ctxtdata *rcd,
         */
        spin_lock(&qp->s_lock);
        qpriv = qp->priv;
+       if (qpriv->r_tid_tail == HFI1_QP_WQE_INVALID ||
+           qpriv->r_tid_tail == qpriv->r_tid_head)
+               goto unlock;
        e = &qp->s_ack_queue[qpriv->r_tid_tail];
+       if (e->opcode != TID_OP(WRITE_REQ))
+               goto unlock;
        req = ack_to_tid_req(e);
+       if (req->comp_seg == req->cur_seg)
+               goto unlock;
        flow = &req->flows[req->clear_tail];
        trace_hfi1_eflags_err_write(qp, rcv_type, rte, psn);
        trace_hfi1_rsp_handle_kdeth_eflags(qp, psn);
@@ -4509,7 +4478,7 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
        struct rvt_swqe *wqe;
        struct tid_rdma_request *req;
        struct tid_rdma_flow *flow;
-       u32 aeth, psn, req_psn, ack_psn, resync_psn, ack_kpsn;
+       u32 aeth, psn, req_psn, ack_psn, flpsn, resync_psn, ack_kpsn;
        unsigned long flags;
        u16 fidx;
 
@@ -4538,6 +4507,9 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
                ack_kpsn--;
        }
 
+       if (unlikely(qp->s_acked == qp->s_tail))
+               goto ack_op_err;
+
        wqe = rvt_get_swqe_ptr(qp, qp->s_acked);
 
        if (wqe->wr.opcode != IB_WR_TID_RDMA_WRITE)
@@ -4550,7 +4522,8 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
        trace_hfi1_tid_flow_rcv_tid_ack(qp, req->acked_tail, flow);
 
        /* Drop stale ACK/NAK */
-       if (cmp_psn(psn, full_flow_psn(flow, flow->flow_state.spsn)) < 0)
+       if (cmp_psn(psn, full_flow_psn(flow, flow->flow_state.spsn)) < 0 ||
+           cmp_psn(req_psn, flow->flow_state.resp_ib_psn) < 0)
                goto ack_op_err;
 
        while (cmp_psn(ack_kpsn,
@@ -4712,7 +4685,12 @@ done:
                switch ((aeth >> IB_AETH_CREDIT_SHIFT) &
                        IB_AETH_CREDIT_MASK) {
                case 0: /* PSN sequence error */
+                       if (!req->flows)
+                               break;
                        flow = &req->flows[req->acked_tail];
+                       flpsn = full_flow_psn(flow, flow->flow_state.lpsn);
+                       if (cmp_psn(psn, flpsn) > 0)
+                               break;
                        trace_hfi1_tid_flow_rcv_tid_ack(qp, req->acked_tail,
                                                        flow);
                        req->r_ack_psn = mask_psn(be32_to_cpu(ohdr->bth[2]));
index 68c9514..5707911 100644 (file)
@@ -1677,8 +1677,6 @@ tx_err:
                                    tx_buf_size, DMA_TO_DEVICE);
                kfree(tun_qp->tx_ring[i].buf.addr);
        }
-       kfree(tun_qp->tx_ring);
-       tun_qp->tx_ring = NULL;
        i = MLX4_NUM_TUNNEL_BUFS;
 err:
        while (i > 0) {
@@ -1687,6 +1685,8 @@ err:
                                    rx_buf_size, DMA_FROM_DEVICE);
                kfree(tun_qp->ring[i].addr);
        }
+       kfree(tun_qp->tx_ring);
+       tun_qp->tx_ring = NULL;
        kfree(tun_qp->ring);
        tun_qp->ring = NULL;
        return -ENOMEM;
index ec4370f..af5bbb3 100644 (file)
@@ -2026,7 +2026,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT)(
                        event_sub->eventfd =
                                eventfd_ctx_fdget(redirect_fd);
 
-                       if (IS_ERR(event_sub)) {
+                       if (IS_ERR(event_sub->eventfd)) {
                                err = PTR_ERR(event_sub->eventfd);
                                event_sub->eventfd = NULL;
                                goto err;
@@ -2644,12 +2644,13 @@ static int devx_async_event_close(struct inode *inode, struct file *filp)
        struct devx_async_event_file *ev_file = filp->private_data;
        struct devx_event_subscription *event_sub, *event_sub_tmp;
        struct devx_async_event_data *entry, *tmp;
+       struct mlx5_ib_dev *dev = ev_file->dev;
 
-       mutex_lock(&ev_file->dev->devx_event_table.event_xa_lock);
+       mutex_lock(&dev->devx_event_table.event_xa_lock);
        /* delete the subscriptions which are related to this FD */
        list_for_each_entry_safe(event_sub, event_sub_tmp,
                                 &ev_file->subscribed_events_list, file_list) {
-               devx_cleanup_subscription(ev_file->dev, event_sub);
+               devx_cleanup_subscription(dev, event_sub);
                if (event_sub->eventfd)
                        eventfd_ctx_put(event_sub->eventfd);
 
@@ -2658,7 +2659,7 @@ static int devx_async_event_close(struct inode *inode, struct file *filp)
                kfree_rcu(event_sub, rcu);
        }
 
-       mutex_unlock(&ev_file->dev->devx_event_table.event_xa_lock);
+       mutex_unlock(&dev->devx_event_table.event_xa_lock);
 
        /* free the pending events allocation */
        if (!ev_file->omit_data) {
@@ -2670,7 +2671,7 @@ static int devx_async_event_close(struct inode *inode, struct file *filp)
        }
 
        uverbs_close_fd(filp);
-       put_device(&ev_file->dev->ib_dev.dev);
+       put_device(&dev->ib_dev.dev);
        return 0;
 }
 
index e12a440..0569bca 100644 (file)
@@ -1023,7 +1023,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        props->timestamp_mask = 0x7FFFFFFFFFFFFFFFULL;
 
        if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
-               if (MLX5_CAP_GEN(mdev, pg))
+               if (dev->odp_caps.general_caps & IB_ODP_SUPPORT)
                        props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING;
                props->odp_caps = dev->odp_caps;
        }
@@ -6139,6 +6139,8 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
                dev->port[i].roce.last_port_state = IB_PORT_DOWN;
        }
 
+       mlx5_ib_internal_fill_odp_caps(dev);
+
        err = mlx5_ib_init_multiport_master(dev);
        if (err)
                return err;
@@ -6563,8 +6565,6 @@ static void mlx5_ib_stage_dev_res_cleanup(struct mlx5_ib_dev *dev)
 
 static int mlx5_ib_stage_odp_init(struct mlx5_ib_dev *dev)
 {
-       mlx5_ib_internal_fill_odp_caps(dev);
-
        return mlx5_ib_odp_init_one(dev);
 }
 
index fe1a76d..a40e0ab 100644 (file)
@@ -57,9 +57,10 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
        int entry;
 
        if (umem->is_odp) {
-               unsigned int page_shift = to_ib_umem_odp(umem)->page_shift;
+               struct ib_umem_odp *odp = to_ib_umem_odp(umem);
+               unsigned int page_shift = odp->page_shift;
 
-               *ncont = ib_umem_page_count(umem);
+               *ncont = ib_umem_odp_num_pages(odp);
                *count = *ncont << (page_shift - PAGE_SHIFT);
                *shift = page_shift;
                if (order)
index f6a5345..9ae587b 100644 (file)
@@ -1475,4 +1475,18 @@ int bfregn_to_uar_index(struct mlx5_ib_dev *dev,
                        bool dyn_bfreg);
 
 int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter);
+
+static inline bool mlx5_ib_can_use_umr(struct mlx5_ib_dev *dev,
+                                      bool do_modify_atomic)
+{
+       if (MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
+               return false;
+
+       if (do_modify_atomic &&
+           MLX5_CAP_GEN(dev->mdev, atomic) &&
+           MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
+               return false;
+
+       return true;
+}
 #endif /* MLX5_IB_H */
index b74fad0..3401f5f 100644 (file)
@@ -1293,9 +1293,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        if (err < 0)
                return ERR_PTR(err);
 
-       use_umr = !MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled) &&
-                 (!MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled) ||
-                  !MLX5_CAP_GEN(dev->mdev, atomic));
+       use_umr = mlx5_ib_can_use_umr(dev, true);
 
        if (order <= mr_cache_max_order(dev) && use_umr) {
                mr = alloc_mr_from_cache(pd, umem, virt_addr, length, ncont,
@@ -1448,7 +1446,8 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
                        goto err;
        }
 
-       if (flags & IB_MR_REREG_TRANS && !use_umr_mtt_update(mr, addr, len)) {
+       if (!mlx5_ib_can_use_umr(dev, true) ||
+           (flags & IB_MR_REREG_TRANS && !use_umr_mtt_update(mr, addr, len))) {
                /*
                 * UMR can't be used - MKey needs to be replaced.
                 */
index 81da820..0a59912 100644 (file)
@@ -301,7 +301,8 @@ void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
 
        memset(caps, 0, sizeof(*caps));
 
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
+       if (!MLX5_CAP_GEN(dev->mdev, pg) ||
+           !mlx5_ib_can_use_umr(dev, true))
                return;
 
        caps->general_caps = IB_ODP_SUPPORT;
@@ -355,7 +356,8 @@ void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)
 
        if (MLX5_CAP_GEN(dev->mdev, fixed_buffer_size) &&
            MLX5_CAP_GEN(dev->mdev, null_mkey) &&
-           MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))
+           MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset) &&
+           !MLX5_CAP_GEN(dev->mdev, umr_indirect_mkey_disabled))
                caps->general_caps |= IB_ODP_SUPPORT_IMPLICIT;
 
        return;
@@ -579,7 +581,6 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
                        u32 flags)
 {
        int npages = 0, current_seq, page_shift, ret, np;
-       bool implicit = false;
        struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem);
        bool downgrade = flags & MLX5_PF_FLAGS_DOWNGRADE;
        bool prefetch = flags & MLX5_PF_FLAGS_PREFETCH;
@@ -594,7 +595,6 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
                if (IS_ERR(odp))
                        return PTR_ERR(odp);
                mr = odp->private;
-               implicit = true;
        } else {
                odp = odp_mr;
        }
@@ -682,19 +682,15 @@ next_mr:
 
 out:
        if (ret == -EAGAIN) {
-               if (implicit || !odp->dying) {
-                       unsigned long timeout =
-                               msecs_to_jiffies(MMU_NOTIFIER_TIMEOUT);
-
-                       if (!wait_for_completion_timeout(
-                                       &odp->notifier_completion,
-                                       timeout)) {
-                               mlx5_ib_warn(dev, "timeout waiting for mmu notifier. seq %d against %d. notifiers_count=%d\n",
-                                            current_seq, odp->notifiers_seq, odp->notifiers_count);
-                       }
-               } else {
-                       /* The MR is being killed, kill the QP as well. */
-                       ret = -EFAULT;
+               unsigned long timeout = msecs_to_jiffies(MMU_NOTIFIER_TIMEOUT);
+
+               if (!wait_for_completion_timeout(&odp->notifier_completion,
+                                                timeout)) {
+                       mlx5_ib_warn(
+                               dev,
+                               "timeout waiting for mmu notifier. seq %d against %d. notifiers_count=%d\n",
+                               current_seq, odp->notifiers_seq,
+                               odp->notifiers_count);
                }
        }
 
@@ -1628,8 +1624,10 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
 {
        int ret = 0;
 
-       if (dev->odp_caps.general_caps & IB_ODP_SUPPORT)
-               ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_odp_ops);
+       if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT))
+               return ret;
+
+       ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_odp_ops);
 
        if (dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT) {
                ret = mlx5_cmd_null_mkey(dev->mdev, &dev->null_mkey);
@@ -1639,9 +1637,6 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
                }
        }
 
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
-               return ret;
-
        ret = mlx5_ib_create_pf_eq(dev, &dev->odp_pf_eq);
 
        return ret;
@@ -1649,7 +1644,7 @@ int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
 
 void mlx5_ib_odp_cleanup_one(struct mlx5_ib_dev *dev)
 {
-       if (!MLX5_CAP_GEN(dev->mdev, pg))
+       if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT))
                return;
 
        mlx5_ib_destroy_pf_eq(dev, &dev->odp_pf_eq);
index 379328b..72869ff 100644 (file)
@@ -4162,7 +4162,7 @@ static u64 get_xlt_octo(u64 bytes)
               MLX5_IB_UMR_OCTOWORD;
 }
 
-static __be64 frwr_mkey_mask(void)
+static __be64 frwr_mkey_mask(bool atomic)
 {
        u64 result;
 
@@ -4175,10 +4175,12 @@ static __be64 frwr_mkey_mask(void)
                MLX5_MKEY_MASK_LW               |
                MLX5_MKEY_MASK_RR               |
                MLX5_MKEY_MASK_RW               |
-               MLX5_MKEY_MASK_A                |
                MLX5_MKEY_MASK_SMALL_FENCE      |
                MLX5_MKEY_MASK_FREE;
 
+       if (atomic)
+               result |= MLX5_MKEY_MASK_A;
+
        return cpu_to_be64(result);
 }
 
@@ -4204,7 +4206,7 @@ static __be64 sig_mkey_mask(void)
 }
 
 static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
-                           struct mlx5_ib_mr *mr, u8 flags)
+                           struct mlx5_ib_mr *mr, u8 flags, bool atomic)
 {
        int size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
 
@@ -4212,7 +4214,7 @@ static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
 
        umr->flags = flags;
        umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size));
-       umr->mkey_mask = frwr_mkey_mask();
+       umr->mkey_mask = frwr_mkey_mask(atomic);
 }
 
 static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
@@ -4811,10 +4813,22 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
 {
        struct mlx5_ib_mr *mr = to_mmr(wr->mr);
        struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
+       struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device);
        int mr_list_size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
        bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD;
+       bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC;
        u8 flags = 0;
 
+       if (!mlx5_ib_can_use_umr(dev, atomic)) {
+               mlx5_ib_warn(to_mdev(qp->ibqp.device),
+                            "Fast update of %s for MR is disabled\n",
+                            (MLX5_CAP_GEN(dev->mdev,
+                                          umr_modify_entity_size_disabled)) ?
+                                    "entity size" :
+                                    "atomic access");
+               return -EINVAL;
+       }
+
        if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
                mlx5_ib_warn(to_mdev(qp->ibqp.device),
                             "Invalid IB_SEND_INLINE send flag\n");
@@ -4826,7 +4840,7 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
        if (umr_inline)
                flags |= MLX5_UMR_INLINE;
 
-       set_reg_umr_seg(*seg, mr, flags);
+       set_reg_umr_seg(*seg, mr, flags, atomic);
        *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
        *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
        handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
index dace276..b622fc6 100644 (file)
@@ -1,6 +1,6 @@
 config RDMA_SIW
        tristate "Software RDMA over TCP/IP (iWARP) driver"
-       depends on INET && INFINIBAND && LIBCRC32C && 64BIT
+       depends on INET && INFINIBAND && LIBCRC32C
        select DMA_VIRT_OPS
        help
        This driver implements the iWARP RDMA transport over
index 03fd7b2..dba4535 100644 (file)
@@ -138,9 +138,9 @@ struct siw_umem {
 };
 
 struct siw_pble {
-       u64 addr; /* Address of assigned user buffer */
-       u64 size; /* Size of this entry */
-       u64 pbl_off; /* Total offset from start of PBL */
+       dma_addr_t addr; /* Address of assigned buffer */
+       unsigned int size; /* Size of this entry */
+       unsigned long pbl_off; /* Total offset from start of PBL */
 };
 
 struct siw_pbl {
@@ -214,7 +214,7 @@ struct siw_wqe {
 struct siw_cq {
        struct ib_cq base_cq;
        spinlock_t lock;
-       u64 *notify;
+       struct siw_cq_ctrl *notify;
        struct siw_cqe *queue;
        u32 cq_put;
        u32 cq_get;
@@ -734,7 +734,7 @@ static inline void siw_crc_skb(struct siw_rx_stream *srx, unsigned int len)
                  "MEM[0x%08x] %s: " fmt, mem->stag, __func__, ##__VA_ARGS__)
 
 #define siw_dbg_cep(cep, fmt, ...)                                             \
-       ibdev_dbg(&cep->sdev->base_dev, "CEP[0x%p] %s: " fmt,                  \
+       ibdev_dbg(&cep->sdev->base_dev, "CEP[0x%pK] %s: " fmt,                  \
                  cep, __func__, ##__VA_ARGS__)
 
 void siw_cq_flush(struct siw_cq *cq);
index 9ce8a1b..8c1931a 100644 (file)
@@ -355,8 +355,8 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
                getname_local(cep->sock, &event.local_addr);
                getname_peer(cep->sock, &event.remote_addr);
        }
-       siw_dbg_cep(cep, "[QP %u]: id 0x%p, reason=%d, status=%d\n",
-                   cep->qp ? qp_id(cep->qp) : -1, id, reason, status);
+       siw_dbg_cep(cep, "[QP %u]: reason=%d, status=%d\n",
+                   cep->qp ? qp_id(cep->qp) : UINT_MAX, reason, status);
 
        return id->event_handler(id, &event);
 }
@@ -947,8 +947,6 @@ static void siw_accept_newconn(struct siw_cep *cep)
        siw_cep_get(new_cep);
        new_s->sk->sk_user_data = new_cep;
 
-       siw_dbg_cep(cep, "listen socket 0x%p, new 0x%p\n", s, new_s);
-
        if (siw_tcp_nagle == false) {
                int val = 1;
 
@@ -1011,7 +1009,8 @@ static void siw_cm_work_handler(struct work_struct *w)
        cep = work->cep;
 
        siw_dbg_cep(cep, "[QP %u]: work type: %d, state %d\n",
-                   cep->qp ? qp_id(cep->qp) : -1, work->type, cep->state);
+                   cep->qp ? qp_id(cep->qp) : UINT_MAX,
+                   work->type, cep->state);
 
        siw_cep_set_inuse(cep);
 
@@ -1145,9 +1144,9 @@ static void siw_cm_work_handler(struct work_struct *w)
        }
        if (release_cep) {
                siw_dbg_cep(cep,
-                           "release: timer=%s, QP[%u], id 0x%p\n",
+                           "release: timer=%s, QP[%u]\n",
                            cep->mpa_timer ? "y" : "n",
-                           cep->qp ? qp_id(cep->qp) : -1, cep->cm_id);
+                           cep->qp ? qp_id(cep->qp) : UINT_MAX);
 
                siw_cancel_mpatimer(cep);
 
@@ -1211,8 +1210,8 @@ int siw_cm_queue_work(struct siw_cep *cep, enum siw_work_type type)
                else
                        delay = MPAREP_TIMEOUT;
        }
-       siw_dbg_cep(cep, "[QP %u]: work type: %d, work 0x%p, timeout %lu\n",
-                   cep->qp ? qp_id(cep->qp) : -1, type, work, delay);
+       siw_dbg_cep(cep, "[QP %u]: work type: %d, timeout %lu\n",
+                   cep->qp ? qp_id(cep->qp) : -1, type, delay);
 
        queue_delayed_work(siw_cm_wq, &work->work, delay);
 
@@ -1376,16 +1375,16 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        }
        if (v4)
                siw_dbg_qp(qp,
-                          "id 0x%p, pd_len %d, laddr %pI4 %d, raddr %pI4 %d\n",
-                          id, pd_len,
+                          "pd_len %d, laddr %pI4 %d, raddr %pI4 %d\n",
+                          pd_len,
                           &((struct sockaddr_in *)(laddr))->sin_addr,
                           ntohs(((struct sockaddr_in *)(laddr))->sin_port),
                           &((struct sockaddr_in *)(raddr))->sin_addr,
                           ntohs(((struct sockaddr_in *)(raddr))->sin_port));
        else
                siw_dbg_qp(qp,
-                          "id 0x%p, pd_len %d, laddr %pI6 %d, raddr %pI6 %d\n",
-                          id, pd_len,
+                          "pd_len %d, laddr %pI6 %d, raddr %pI6 %d\n",
+                          pd_len,
                           &((struct sockaddr_in6 *)(laddr))->sin6_addr,
                           ntohs(((struct sockaddr_in6 *)(laddr))->sin6_port),
                           &((struct sockaddr_in6 *)(raddr))->sin6_addr,
@@ -1508,14 +1507,13 @@ int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (rv >= 0) {
                rv = siw_cm_queue_work(cep, SIW_CM_WORK_MPATIMEOUT);
                if (!rv) {
-                       siw_dbg_cep(cep, "id 0x%p, [QP %u]: exit\n", id,
-                                   qp_id(qp));
+                       siw_dbg_cep(cep, "[QP %u]: exit\n", qp_id(qp));
                        siw_cep_set_free(cep);
                        return 0;
                }
        }
 error:
-       siw_dbg_qp(qp, "failed: %d\n", rv);
+       siw_dbg(id->device, "failed: %d\n", rv);
 
        if (cep) {
                siw_socket_disassoc(s);
@@ -1540,7 +1538,8 @@ error:
        } else if (s) {
                sock_release(s);
        }
-       siw_qp_put(qp);
+       if (qp)
+               siw_qp_put(qp);
 
        return rv;
 }
@@ -1580,7 +1579,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        siw_cancel_mpatimer(cep);
 
        if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
-               siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+               siw_dbg_cep(cep, "out of state\n");
 
                siw_cep_set_free(cep);
                siw_cep_put(cep);
@@ -1601,7 +1600,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
                up_write(&qp->state_lock);
                goto error;
        }
-       siw_dbg_cep(cep, "id 0x%p\n", id);
+       siw_dbg_cep(cep, "[QP %d]\n", params->qpn);
 
        if (try_gso && cep->mpa.hdr.params.bits & MPA_RR_FLAG_GSO_EXP) {
                siw_dbg_cep(cep, "peer allows GSO on TX\n");
@@ -1611,8 +1610,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
            params->ird > sdev->attrs.max_ird) {
                siw_dbg_cep(
                        cep,
-                       "id 0x%p, [QP %u]: ord %d (max %d), ird %d (max %d)\n",
-                       id, qp_id(qp), params->ord, sdev->attrs.max_ord,
+                       "[QP %u]: ord %d (max %d), ird %d (max %d)\n",
+                       qp_id(qp), params->ord, sdev->attrs.max_ord,
                        params->ird, sdev->attrs.max_ird);
                rv = -EINVAL;
                up_write(&qp->state_lock);
@@ -1624,8 +1623,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (params->private_data_len > max_priv_data) {
                siw_dbg_cep(
                        cep,
-                       "id 0x%p, [QP %u]: private data length: %d (max %d)\n",
-                       id, qp_id(qp), params->private_data_len, max_priv_data);
+                       "[QP %u]: private data length: %d (max %d)\n",
+                       qp_id(qp), params->private_data_len, max_priv_data);
                rv = -EINVAL;
                up_write(&qp->state_lock);
                goto error;
@@ -1679,7 +1678,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
                qp_attrs.flags = SIW_MPA_CRC;
        qp_attrs.state = SIW_QP_STATE_RTS;
 
-       siw_dbg_cep(cep, "id 0x%p, [QP%u]: moving to rts\n", id, qp_id(qp));
+       siw_dbg_cep(cep, "[QP%u]: moving to rts\n", qp_id(qp));
 
        /* Associate QP with CEP */
        siw_cep_get(cep);
@@ -1700,8 +1699,8 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
        if (rv)
                goto error;
 
-       siw_dbg_cep(cep, "id 0x%p, [QP %u]: send mpa reply, %d byte pdata\n",
-                   id, qp_id(qp), params->private_data_len);
+       siw_dbg_cep(cep, "[QP %u]: send mpa reply, %d byte pdata\n",
+                   qp_id(qp), params->private_data_len);
 
        rv = siw_send_mpareqrep(cep, params->private_data,
                                params->private_data_len);
@@ -1759,14 +1758,14 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len)
        siw_cancel_mpatimer(cep);
 
        if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
-               siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+               siw_dbg_cep(cep, "out of state\n");
 
                siw_cep_set_free(cep);
                siw_cep_put(cep); /* put last reference */
 
                return -ECONNRESET;
        }
-       siw_dbg_cep(cep, "id 0x%p, cep->state %d, pd_len %d\n", id, cep->state,
+       siw_dbg_cep(cep, "cep->state %d, pd_len %d\n", cep->state,
                    pd_len);
 
        if (__mpa_rr_revision(cep->mpa.hdr.params.bits) >= MPA_REVISION_1) {
@@ -1804,14 +1803,14 @@ static int siw_listen_address(struct iw_cm_id *id, int backlog,
        rv = kernel_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&s_val,
                               sizeof(s_val));
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: setsockopt error: %d\n", id, rv);
+               siw_dbg(id->device, "setsockopt error: %d\n", rv);
                goto error;
        }
        rv = s->ops->bind(s, laddr, addr_family == AF_INET ?
                                    sizeof(struct sockaddr_in) :
                                    sizeof(struct sockaddr_in6));
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: socket bind error: %d\n", id, rv);
+               siw_dbg(id->device, "socket bind error: %d\n", rv);
                goto error;
        }
        cep = siw_cep_alloc(sdev);
@@ -1824,13 +1823,13 @@ static int siw_listen_address(struct iw_cm_id *id, int backlog,
        rv = siw_cm_alloc_work(cep, backlog);
        if (rv) {
                siw_dbg(id->device,
-                       "id 0x%p: alloc_work error %d, backlog %d\n", id,
+                       "alloc_work error %d, backlog %d\n",
                        rv, backlog);
                goto error;
        }
        rv = s->ops->listen(s, backlog);
        if (rv) {
-               siw_dbg(id->device, "id 0x%p: listen error %d\n", id, rv);
+               siw_dbg(id->device, "listen error %d\n", rv);
                goto error;
        }
        cep->cm_id = id;
@@ -1914,8 +1913,7 @@ static void siw_drop_listeners(struct iw_cm_id *id)
 
                list_del(p);
 
-               siw_dbg_cep(cep, "id 0x%p: drop cep, state %d\n", id,
-                           cep->state);
+               siw_dbg_cep(cep, "drop cep, state %d\n", cep->state);
 
                siw_cep_set_inuse(cep);
 
@@ -1952,7 +1950,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
        struct net_device *dev = to_siw_dev(id->device)->netdev;
        int rv = 0, listeners = 0;
 
-       siw_dbg(id->device, "id 0x%p: backlog %d\n", id, backlog);
+       siw_dbg(id->device, "backlog %d\n", backlog);
 
        /*
         * For each attached address of the interface, create a
@@ -1964,12 +1962,16 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
                struct sockaddr_in s_laddr, *s_raddr;
                const struct in_ifaddr *ifa;
 
+               if (!in_dev) {
+                       rv = -ENODEV;
+                       goto out;
+               }
                memcpy(&s_laddr, &id->local_addr, sizeof(s_laddr));
                s_raddr = (struct sockaddr_in *)&id->remote_addr;
 
                siw_dbg(id->device,
-                       "id 0x%p: laddr %pI4:%d, raddr %pI4:%d\n",
-                       id, &s_laddr.sin_addr, ntohs(s_laddr.sin_port),
+                       "laddr %pI4:%d, raddr %pI4:%d\n",
+                       &s_laddr.sin_addr, ntohs(s_laddr.sin_port),
                        &s_raddr->sin_addr, ntohs(s_raddr->sin_port));
 
                rtnl_lock();
@@ -1993,22 +1995,27 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
                struct sockaddr_in6 *s_laddr = &to_sockaddr_in6(id->local_addr),
                        *s_raddr = &to_sockaddr_in6(id->remote_addr);
 
+               if (!in6_dev) {
+                       rv = -ENODEV;
+                       goto out;
+               }
                siw_dbg(id->device,
-                       "id 0x%p: laddr %pI6:%d, raddr %pI6:%d\n",
-                       id, &s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
+                       "laddr %pI6:%d, raddr %pI6:%d\n",
+                       &s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
                        &s_raddr->sin6_addr, ntohs(s_raddr->sin6_port));
 
-               read_lock_bh(&in6_dev->lock);
+               rtnl_lock();
                list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
-                       struct sockaddr_in6 bind_addr;
-
+                       if (ifp->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
+                               continue;
                        if (ipv6_addr_any(&s_laddr->sin6_addr) ||
                            ipv6_addr_equal(&s_laddr->sin6_addr, &ifp->addr)) {
-                               bind_addr.sin6_family = AF_INET6;
-                               bind_addr.sin6_port = s_laddr->sin6_port;
-                               bind_addr.sin6_flowinfo = 0;
-                               bind_addr.sin6_addr = ifp->addr;
-                               bind_addr.sin6_scope_id = dev->ifindex;
+                               struct sockaddr_in6 bind_addr  = {
+                                       .sin6_family = AF_INET6,
+                                       .sin6_port = s_laddr->sin6_port,
+                                       .sin6_flowinfo = 0,
+                                       .sin6_addr = ifp->addr,
+                                       .sin6_scope_id = dev->ifindex };
 
                                rv = siw_listen_address(id, backlog,
                                                (struct sockaddr *)&bind_addr,
@@ -2017,28 +2024,26 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
                                        listeners++;
                        }
                }
-               read_unlock_bh(&in6_dev->lock);
-
+               rtnl_unlock();
                in6_dev_put(in6_dev);
        } else {
-               return -EAFNOSUPPORT;
+               rv = -EAFNOSUPPORT;
        }
+out:
        if (listeners)
                rv = 0;
        else if (!rv)
                rv = -EINVAL;
 
-       siw_dbg(id->device, "id 0x%p: %s\n", id, rv ? "FAIL" : "OK");
+       siw_dbg(id->device, "%s\n", rv ? "FAIL" : "OK");
 
        return rv;
 }
 
 int siw_destroy_listen(struct iw_cm_id *id)
 {
-       siw_dbg(id->device, "id 0x%p\n", id);
-
        if (!id->provider_data) {
-               siw_dbg(id->device, "id 0x%p: no cep(s)\n", id);
+               siw_dbg(id->device, "no cep(s)\n");
                return 0;
        }
        siw_drop_listeners(id);
index e381ae9..d8db3be 100644 (file)
@@ -71,9 +71,10 @@ int siw_reap_cqe(struct siw_cq *cq, struct ib_wc *wc)
                                wc->wc_flags = IB_WC_WITH_INVALIDATE;
                        }
                        wc->qp = cqe->base_qp;
-                       siw_dbg_cq(cq, "idx %u, type %d, flags %2x, id 0x%p\n",
+                       siw_dbg_cq(cq,
+                                  "idx %u, type %d, flags %2x, id 0x%pK\n",
                                   cq->cq_get % cq->num_cqe, cqe->opcode,
-                                  cqe->flags, (void *)cqe->id);
+                                  cqe->flags, (void *)(uintptr_t)cqe->id);
                }
                WRITE_ONCE(cqe->flags, 0);
                cq->cq_get++;
index d0f140d..05a92f9 100644 (file)
@@ -160,10 +160,8 @@ static int siw_init_cpulist(void)
 
 out_err:
        siw_cpu_info.num_nodes = 0;
-       while (i) {
+       while (--i >= 0)
                kfree(siw_cpu_info.tx_valid_cpus[i]);
-               siw_cpu_info.tx_valid_cpus[i--] = NULL;
-       }
        kfree(siw_cpu_info.tx_valid_cpus);
        siw_cpu_info.tx_valid_cpus = NULL;
 
index 67171c8..87a5603 100644 (file)
@@ -197,12 +197,12 @@ int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr,
         */
        if (addr < mem->va || addr + len > mem->va + mem->len) {
                siw_dbg_pd(pd, "MEM interval len %d\n", len);
-               siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] out of bounds\n",
-                          (unsigned long long)addr,
-                          (unsigned long long)(addr + len));
-               siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] STag=0x%08x\n",
-                          (unsigned long long)mem->va,
-                          (unsigned long long)(mem->va + mem->len),
+               siw_dbg_pd(pd, "[0x%pK, 0x%pK] out of bounds\n",
+                          (void *)(uintptr_t)addr,
+                          (void *)(uintptr_t)(addr + len));
+               siw_dbg_pd(pd, "[0x%pK, 0x%pK] STag=0x%08x\n",
+                          (void *)(uintptr_t)mem->va,
+                          (void *)(uintptr_t)(mem->va + mem->len),
                           mem->stag);
 
                return -E_BASE_BOUNDS;
@@ -330,7 +330,7 @@ out:
  * Optionally, provides remaining len within current element, and
  * current PBL index for later resume at same element.
  */
-u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx)
+dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx)
 {
        int i = idx ? *idx : 0;
 
index f43daf2..db138c8 100644 (file)
@@ -9,7 +9,7 @@
 struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable);
 void siw_umem_release(struct siw_umem *umem, bool dirty);
 struct siw_pbl *siw_pbl_alloc(u32 num_buf);
-u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
+dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
 struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index);
 int siw_mem_add(struct siw_device *sdev, struct siw_mem *m);
 int siw_invalidate_stag(struct ib_pd *pd, u32 stag);
index e27bd5b..430314c 100644 (file)
@@ -949,7 +949,7 @@ skip_irq:
                                rv = -EINVAL;
                                goto out;
                        }
-                       wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+                       wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
                        wqe->sqe.sge[0].lkey = 0;
                        wqe->sqe.num_sge = 1;
                }
@@ -1013,18 +1013,24 @@ out:
  */
 static bool siw_cq_notify_now(struct siw_cq *cq, u32 flags)
 {
-       u64 cq_notify;
+       u32 cq_notify;
 
        if (!cq->base_cq.comp_handler)
                return false;
 
-       cq_notify = READ_ONCE(*cq->notify);
+       /* Read application shared notification state */
+       cq_notify = READ_ONCE(cq->notify->flags);
 
        if ((cq_notify & SIW_NOTIFY_NEXT_COMPLETION) ||
            ((cq_notify & SIW_NOTIFY_SOLICITED) &&
             (flags & SIW_WQE_SOLICITED))) {
-               /* dis-arm CQ */
-               smp_store_mb(*cq->notify, SIW_NOTIFY_NOT);
+               /*
+                * CQ notification is one-shot: Since the
+                * current CQE causes user notification,
+                * the CQ gets dis-aremd and must be re-aremd
+                * by the user for a new notification.
+                */
+               WRITE_ONCE(cq->notify->flags, SIW_NOTIFY_NOT);
 
                return true;
        }
index f87657a..c0a8872 100644 (file)
@@ -38,9 +38,10 @@ static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
 
                p = siw_get_upage(umem, dest_addr);
                if (unlikely(!p)) {
-                       pr_warn("siw: %s: [QP %u]: bogus addr: %p, %p\n",
+                       pr_warn("siw: %s: [QP %u]: bogus addr: %pK, %pK\n",
                                __func__, qp_id(rx_qp(srx)),
-                               (void *)dest_addr, (void *)umem->fp_addr);
+                               (void *)(uintptr_t)dest_addr,
+                               (void *)(uintptr_t)umem->fp_addr);
                        /* siw internal error */
                        srx->skb_copied += copied;
                        srx->skb_new -= copied;
@@ -50,7 +51,7 @@ static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
                pg_off = dest_addr & ~PAGE_MASK;
                bytes = min(len, (int)PAGE_SIZE - pg_off);
 
-               siw_dbg_qp(rx_qp(srx), "page %p, bytes=%u\n", p, bytes);
+               siw_dbg_qp(rx_qp(srx), "page %pK, bytes=%u\n", p, bytes);
 
                dest = kmap_atomic(p);
                rv = skb_copy_bits(srx->skb, srx->skb_offset, dest + pg_off,
@@ -104,11 +105,11 @@ static int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len)
 {
        int rv;
 
-       siw_dbg_qp(rx_qp(srx), "kva: 0x%p, len: %u\n", kva, len);
+       siw_dbg_qp(rx_qp(srx), "kva: 0x%pK, len: %u\n", kva, len);
 
        rv = skb_copy_bits(srx->skb, srx->skb_offset, kva, len);
        if (unlikely(rv)) {
-               pr_warn("siw: [QP %u]: %s, len %d, kva 0x%p, rv %d\n",
+               pr_warn("siw: [QP %u]: %s, len %d, kva 0x%pK, rv %d\n",
                        qp_id(rx_qp(srx)), __func__, len, kva, rv);
 
                return rv;
@@ -132,7 +133,7 @@ static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx,
 
        while (len) {
                int bytes;
-               u64 buf_addr =
+               dma_addr_t buf_addr =
                        siw_pbl_get_buffer(pbl, offset, &bytes, pbl_idx);
                if (!buf_addr)
                        break;
@@ -485,8 +486,8 @@ int siw_proc_send(struct siw_qp *qp)
                mem_p = *mem;
                if (mem_p->mem_obj == NULL)
                        rv = siw_rx_kva(srx,
-                                       (void *)(sge->laddr + frx->sge_off),
-                                       sge_bytes);
+                               (void *)(uintptr_t)(sge->laddr + frx->sge_off),
+                               sge_bytes);
                else if (!mem_p->is_pbl)
                        rv = siw_rx_umem(srx, mem_p->umem,
                                         sge->laddr + frx->sge_off, sge_bytes);
@@ -598,8 +599,8 @@ int siw_proc_write(struct siw_qp *qp)
 
        if (mem->mem_obj == NULL)
                rv = siw_rx_kva(srx,
-                               (void *)(srx->ddp_to + srx->fpdu_part_rcvd),
-                               bytes);
+                       (void *)(uintptr_t)(srx->ddp_to + srx->fpdu_part_rcvd),
+                       bytes);
        else if (!mem->is_pbl)
                rv = siw_rx_umem(srx, mem->umem,
                                 srx->ddp_to + srx->fpdu_part_rcvd, bytes);
@@ -841,8 +842,9 @@ int siw_proc_rresp(struct siw_qp *qp)
        bytes = min(srx->fpdu_part_rem, srx->skb_new);
 
        if (mem_p->mem_obj == NULL)
-               rv = siw_rx_kva(srx, (void *)(sge->laddr + wqe->processed),
-                               bytes);
+               rv = siw_rx_kva(srx,
+                       (void *)(uintptr_t)(sge->laddr + wqe->processed),
+                       bytes);
        else if (!mem_p->is_pbl)
                rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed,
                                 bytes);
index 43020d2..438a291 100644 (file)
@@ -26,7 +26,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
 {
        struct siw_pbl *pbl = mem->pbl;
        u64 offset = addr - mem->va;
-       u64 paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
+       dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
 
        if (paddr)
                return virt_to_page(paddr);
@@ -37,7 +37,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
 /*
  * Copy short payload at provided destination payload address
  */
-static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
+static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr)
 {
        struct siw_wqe *wqe = &c_tx->wqe_active;
        struct siw_sge *sge = &wqe->sqe.sge[0];
@@ -50,16 +50,16 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                return 0;
 
        if (tx_flags(wqe) & SIW_WQE_INLINE) {
-               memcpy((void *)paddr, &wqe->sqe.sge[1], bytes);
+               memcpy(paddr, &wqe->sqe.sge[1], bytes);
        } else {
                struct siw_mem *mem = wqe->mem[0];
 
                if (!mem->mem_obj) {
                        /* Kernel client using kva */
-                       memcpy((void *)paddr, (void *)sge->laddr, bytes);
+                       memcpy(paddr,
+                              (const void *)(uintptr_t)sge->laddr, bytes);
                } else if (c_tx->in_syscall) {
-                       if (copy_from_user((void *)paddr,
-                                          (const void __user *)sge->laddr,
+                       if (copy_from_user(paddr, u64_to_user_ptr(sge->laddr),
                                           bytes))
                                return -EFAULT;
                } else {
@@ -79,12 +79,12 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                        buffer = kmap_atomic(p);
 
                        if (likely(PAGE_SIZE - off >= bytes)) {
-                               memcpy((void *)paddr, buffer + off, bytes);
+                               memcpy(paddr, buffer + off, bytes);
                                kunmap_atomic(buffer);
                        } else {
                                unsigned long part = bytes - (PAGE_SIZE - off);
 
-                               memcpy((void *)paddr, buffer + off, part);
+                               memcpy(paddr, buffer + off, part);
                                kunmap_atomic(buffer);
 
                                if (!mem->is_pbl)
@@ -98,7 +98,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
                                        return -EFAULT;
 
                                buffer = kmap_atomic(p);
-                               memcpy((void *)(paddr + part), buffer,
+                               memcpy(paddr + part, buffer,
                                       bytes - part);
                                kunmap_atomic(buffer);
                        }
@@ -166,7 +166,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_send);
 
                crc = (char *)&c_tx->pkt.send_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_SEND_REMOTE_INV:
@@ -189,7 +189,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_send_inv);
 
                crc = (char *)&c_tx->pkt.send_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_WRITE:
@@ -201,7 +201,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_rdma_write);
 
                crc = (char *)&c_tx->pkt.write_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        case SIW_OP_READ_RESPONSE:
@@ -216,7 +216,7 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
                c_tx->ctrl_len = sizeof(struct iwarp_rdma_rresp);
 
                crc = (char *)&c_tx->pkt.write_pkt.crc;
-               data = siw_try_1seg(c_tx, (u64)crc);
+               data = siw_try_1seg(c_tx, crc);
                break;
 
        default:
@@ -398,15 +398,13 @@ static int siw_0copy_tx(struct socket *s, struct page **page,
 
 #define MAX_TRAILER (MPA_CRC_SIZE + 4)
 
-static void siw_unmap_pages(struct page **pages, int hdr_len, int num_maps)
+static void siw_unmap_pages(struct page **pp, unsigned long kmap_mask)
 {
-       if (hdr_len) {
-               ++pages;
-               --num_maps;
-       }
-       while (num_maps-- > 0) {
-               kunmap(*pages);
-               pages++;
+       while (kmap_mask) {
+               if (kmap_mask & BIT(0))
+                       kunmap(*pp);
+               pp++;
+               kmap_mask >>= 1;
        }
 }
 
@@ -437,6 +435,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
        unsigned int data_len = c_tx->bytes_unsent, hdr_len = 0, trl_len = 0,
                     sge_off = c_tx->sge_off, sge_idx = c_tx->sge_idx,
                     pbl_idx = c_tx->pbl_idx;
+       unsigned long kmap_mask = 0L;
 
        if (c_tx->state == SIW_SEND_HDR) {
                if (c_tx->use_sendpage) {
@@ -463,8 +462,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
 
                if (!(tx_flags(wqe) & SIW_WQE_INLINE)) {
                        mem = wqe->mem[sge_idx];
-                       if (!mem->mem_obj)
-                               is_kva = 1;
+                       is_kva = mem->mem_obj == NULL ? 1 : 0;
                } else {
                        is_kva = 1;
                }
@@ -473,7 +471,8 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                         * tx from kernel virtual address: either inline data
                         * or memory region with assigned kernel buffer
                         */
-                       iov[seg].iov_base = (void *)(sge->laddr + sge_off);
+                       iov[seg].iov_base =
+                               (void *)(uintptr_t)(sge->laddr + sge_off);
                        iov[seg].iov_len = sge_len;
 
                        if (do_crc)
@@ -500,12 +499,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                        p = siw_get_upage(mem->umem,
                                                          sge->laddr + sge_off);
                                if (unlikely(!p)) {
-                                       if (hdr_len)
-                                               seg--;
-                                       if (!c_tx->use_sendpage && seg) {
-                                               siw_unmap_pages(page_array,
-                                                               hdr_len, seg);
-                                       }
+                                       siw_unmap_pages(page_array, kmap_mask);
                                        wqe->processed -= c_tx->bytes_unsent;
                                        rv = -EFAULT;
                                        goto done_crc;
@@ -515,6 +509,10 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                if (!c_tx->use_sendpage) {
                                        iov[seg].iov_base = kmap(p) + fp_off;
                                        iov[seg].iov_len = plen;
+
+                                       /* Remember for later kunmap() */
+                                       kmap_mask |= BIT(seg);
+
                                        if (do_crc)
                                                crypto_shash_update(
                                                        c_tx->mpa_crc_hd,
@@ -526,13 +524,13 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
                                                page_address(p) + fp_off,
                                                plen);
                        } else {
-                               u64 pa = ((sge->laddr + sge_off) & PAGE_MASK);
+                               u64 va = sge->laddr + sge_off;
 
-                               page_array[seg] = virt_to_page(pa);
+                               page_array[seg] = virt_to_page(va & PAGE_MASK);
                                if (do_crc)
                                        crypto_shash_update(
                                                c_tx->mpa_crc_hd,
-                                               (void *)(sge->laddr + sge_off),
+                                               (void *)(uintptr_t)va,
                                                plen);
                        }
 
@@ -543,10 +541,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
 
                        if (++seg > (int)MAX_ARRAY) {
                                siw_dbg_qp(tx_qp(c_tx), "to many fragments\n");
-                               if (!is_kva && !c_tx->use_sendpage) {
-                                       siw_unmap_pages(page_array, hdr_len,
-                                                       seg - 1);
-                               }
+                               siw_unmap_pages(page_array, kmap_mask);
                                wqe->processed -= c_tx->bytes_unsent;
                                rv = -EMSGSIZE;
                                goto done_crc;
@@ -597,8 +592,7 @@ sge_done:
        } else {
                rv = kernel_sendmsg(s, &msg, iov, seg + 1,
                                    hdr_len + data_len + trl_len);
-               if (!is_kva)
-                       siw_unmap_pages(page_array, hdr_len, seg);
+               siw_unmap_pages(page_array, kmap_mask);
        }
        if (rv < (int)hdr_len) {
                /* Not even complete hdr pushed or negative rv */
@@ -829,7 +823,8 @@ static int siw_qp_sq_proc_tx(struct siw_qp *qp, struct siw_wqe *wqe)
                                        rv = -EINVAL;
                                        goto tx_error;
                                }
-                               wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+                               wqe->sqe.sge[0].laddr =
+                                       (u64)(uintptr_t)&wqe->sqe.sge[1];
                        }
                }
                wqe->wr_status = SIW_WR_INPROGRESS;
@@ -924,7 +919,7 @@ tx_error:
 
 static int siw_fastreg_mr(struct ib_pd *pd, struct siw_sqe *sqe)
 {
-       struct ib_mr *base_mr = (struct ib_mr *)sqe->base_mr;
+       struct ib_mr *base_mr = (struct ib_mr *)(uintptr_t)sqe->base_mr;
        struct siw_device *sdev = to_siw_dev(pd->device);
        struct siw_mem *mem = siw_mem_id2obj(sdev, sqe->rkey  >> 8);
        int rv = 0;
@@ -954,8 +949,7 @@ static int siw_fastreg_mr(struct ib_pd *pd, struct siw_sqe *sqe)
        mem->stag = sqe->rkey;
        mem->perms = sqe->access;
 
-       siw_dbg_mem(mem, "STag now valid, MR va: 0x%016llx -> 0x%016llx\n",
-                   mem->va, base_mr->iova);
+       siw_dbg_mem(mem, "STag 0x%08x now valid\n", sqe->rkey);
        mem->va = base_mr->iova;
        mem->stag_valid = 1;
 out:
index 32dc79d..da52c90 100644 (file)
@@ -424,8 +424,7 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
                 */
                qp->srq = to_siw_srq(attrs->srq);
                qp->attrs.rq_size = 0;
-               siw_dbg(base_dev, "QP [%u]: [SRQ 0x%p] attached\n",
-                       qp->qp_num, qp->srq);
+               siw_dbg(base_dev, "QP [%u]: SRQ attached\n", qp->qp_num);
        } else if (num_rqe) {
                if (qp->kernel_verbs)
                        qp->recvq = vzalloc(num_rqe * sizeof(struct siw_rqe));
@@ -610,7 +609,7 @@ int siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata)
                                          base_ucontext);
        struct siw_qp_attrs qp_attrs;
 
-       siw_dbg_qp(qp, "state %d, cep 0x%p\n", qp->attrs.state, qp->cep);
+       siw_dbg_qp(qp, "state %d\n", qp->attrs.state);
 
        /*
         * Mark QP as in process of destruction to prevent from
@@ -662,7 +661,7 @@ static int siw_copy_inline_sgl(const struct ib_send_wr *core_wr,
        void *kbuf = &sqe->sge[1];
        int num_sge = core_wr->num_sge, bytes = 0;
 
-       sqe->sge[0].laddr = (u64)kbuf;
+       sqe->sge[0].laddr = (uintptr_t)kbuf;
        sqe->sge[0].lkey = 0;
 
        while (num_sge--) {
@@ -825,7 +824,7 @@ int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
                        break;
 
                case IB_WR_REG_MR:
-                       sqe->base_mr = (uint64_t)reg_wr(wr)->mr;
+                       sqe->base_mr = (uintptr_t)reg_wr(wr)->mr;
                        sqe->rkey = reg_wr(wr)->key;
                        sqe->access = reg_wr(wr)->access & IWARP_ACCESS_MASK;
                        sqe->opcode = SIW_OP_REG_MR;
@@ -842,8 +841,9 @@ int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
                        rv = -EINVAL;
                        break;
                }
-               siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%p\n",
-                          sqe->opcode, sqe->flags, (void *)sqe->id);
+               siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%pK\n",
+                          sqe->opcode, sqe->flags,
+                          (void *)(uintptr_t)sqe->id);
 
                if (unlikely(rv < 0))
                        break;
@@ -1049,7 +1049,7 @@ int siw_create_cq(struct ib_cq *base_cq, const struct ib_cq_init_attr *attr,
 
        spin_lock_init(&cq->lock);
 
-       cq->notify = &((struct siw_cq_ctrl *)&cq->queue[size])->notify;
+       cq->notify = (struct siw_cq_ctrl *)&cq->queue[size];
 
        if (udata) {
                struct siw_uresp_create_cq uresp = {};
@@ -1141,11 +1141,17 @@ int siw_req_notify_cq(struct ib_cq *base_cq, enum ib_cq_notify_flags flags)
        siw_dbg_cq(cq, "flags: 0x%02x\n", flags);
 
        if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
-               /* CQ event for next solicited completion */
-               smp_store_mb(*cq->notify, SIW_NOTIFY_SOLICITED);
+               /*
+                * Enable CQ event for next solicited completion.
+                * and make it visible to all associated producers.
+                */
+               smp_store_mb(cq->notify->flags, SIW_NOTIFY_SOLICITED);
        else
-               /* CQ event for any signalled completion */
-               smp_store_mb(*cq->notify, SIW_NOTIFY_ALL);
+               /*
+                * Enable CQ event for any signalled completion.
+                * and make it visible to all associated producers.
+                */
+               smp_store_mb(cq->notify->flags, SIW_NOTIFY_ALL);
 
        if (flags & IB_CQ_REPORT_MISSED_EVENTS)
                return cq->cq_put - cq->cq_get;
@@ -1199,8 +1205,8 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
        unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK);
        int rv;
 
-       siw_dbg_pd(pd, "start: 0x%016llx, va: 0x%016llx, len: %llu\n",
-                  (unsigned long long)start, (unsigned long long)rnic_va,
+       siw_dbg_pd(pd, "start: 0x%pK, va: 0x%pK, len: %llu\n",
+                  (void *)(uintptr_t)start, (void *)(uintptr_t)rnic_va,
                   (unsigned long long)len);
 
        if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
@@ -1357,7 +1363,7 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
        struct siw_mem *mem = mr->mem;
        struct siw_pbl *pbl = mem->pbl;
        struct siw_pble *pble;
-       u64 pbl_size;
+       unsigned long pbl_size;
        int i, rv;
 
        if (!pbl) {
@@ -1396,16 +1402,18 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
                        pbl_size += sg_dma_len(slp);
                }
                siw_dbg_mem(mem,
-                       "sge[%d], size %llu, addr 0x%016llx, total %llu\n",
-                       i, pble->size, pble->addr, pbl_size);
+                       "sge[%d], size %u, addr 0x%p, total %lu\n",
+                       i, pble->size, (void *)(uintptr_t)pble->addr,
+                       pbl_size);
        }
        rv = ib_sg_to_pages(base_mr, sl, num_sle, sg_off, siw_set_pbl_page);
        if (rv > 0) {
                mem->len = base_mr->length;
                mem->va = base_mr->iova;
                siw_dbg_mem(mem,
-                       "%llu bytes, start 0x%016llx, %u SLE to %u entries\n",
-                       mem->len, mem->va, num_sle, pbl->num_buf);
+                       "%llu bytes, start 0x%pK, %u SLE to %u entries\n",
+                       mem->len, (void *)(uintptr_t)mem->va, num_sle,
+                       pbl->num_buf);
        }
        return rv;
 }
@@ -1523,7 +1531,7 @@ int siw_create_srq(struct ib_srq *base_srq,
        }
        spin_lock_init(&srq->lock);
 
-       siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: success\n", srq);
+       siw_dbg_pd(base_srq->pd, "[SRQ]: success\n");
 
        return 0;
 
@@ -1644,8 +1652,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
 
        if (unlikely(!srq->kernel_verbs)) {
                siw_dbg_pd(base_srq->pd,
-                          "[SRQ 0x%p]: no kernel post_recv for mapped srq\n",
-                          srq);
+                          "[SRQ]: no kernel post_recv for mapped srq\n");
                rv = -EINVAL;
                goto out;
        }
@@ -1667,8 +1674,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
                }
                if (unlikely(wr->num_sge > srq->max_sge)) {
                        siw_dbg_pd(base_srq->pd,
-                                  "[SRQ 0x%p]: too many sge's: %d\n", srq,
-                                  wr->num_sge);
+                                  "[SRQ]: too many sge's: %d\n", wr->num_sge);
                        rv = -EINVAL;
                        break;
                }
@@ -1687,7 +1693,7 @@ int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
        spin_unlock_irqrestore(&srq->lock, flags);
 out:
        if (unlikely(rv < 0)) {
-               siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: error %d\n", srq, rv);
+               siw_dbg_pd(base_srq->pd, "[SRQ]: error %d\n", rv);
                *bad_wr = wr;
        }
        return rv;
index 88ae7c2..e486a8a 100644 (file)
@@ -237,40 +237,17 @@ static void hv_kbd_handle_received_packet(struct hv_device *hv_dev,
 
 static void hv_kbd_on_channel_callback(void *context)
 {
+       struct vmpacket_descriptor *desc;
        struct hv_device *hv_dev = context;
-       void *buffer;
-       int bufferlen = 0x100; /* Start with sensible size */
        u32 bytes_recvd;
        u64 req_id;
-       int error;
 
-       buffer = kmalloc(bufferlen, GFP_ATOMIC);
-       if (!buffer)
-               return;
-
-       while (1) {
-               error = vmbus_recvpacket_raw(hv_dev->channel, buffer, bufferlen,
-                                            &bytes_recvd, &req_id);
-               switch (error) {
-               case 0:
-                       if (bytes_recvd == 0) {
-                               kfree(buffer);
-                               return;
-                       }
-
-                       hv_kbd_handle_received_packet(hv_dev, buffer,
-                                                     bytes_recvd, req_id);
-                       break;
+       foreach_vmbus_pkt(desc, hv_dev->channel) {
+               bytes_recvd = desc->len8 * 8;
+               req_id = desc->trans_id;
 
-               case -ENOBUFS:
-                       kfree(buffer);
-                       /* Handle large packet */
-                       bufferlen = bytes_recvd;
-                       buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
-                       if (!buffer)
-                               return;
-                       break;
-               }
+               hv_kbd_handle_received_packet(hv_dev, desc, bytes_recvd,
+                                             req_id);
        }
 }
 
index e15cdcd..e3842ea 100644 (file)
@@ -177,11 +177,12 @@ config DMAR_TABLE
 
 config INTEL_IOMMU
        bool "Support for Intel IOMMU using DMA Remapping Devices"
-       depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
+       depends on PCI_MSI && ACPI && (X86 || IA64)
        select IOMMU_API
        select IOMMU_IOVA
        select NEED_DMA_MAP_STATE
        select DMAR_TABLE
+       select SWIOTLB
        help
          DMA remapping (DMAR) devices support enables independent address
          translations for Direct Memory Access (DMA) from devices.
index f13f36a..4f405f9 100644 (file)
@@ -10,13 +10,14 @@ obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
 obj-$(CONFIG_IOMMU_IOVA) += iova.o
 obj-$(CONFIG_OF_IOMMU) += of_iommu.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o
-obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
+obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o amd_iommu_quirks.o
 obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd_iommu_debugfs.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
-obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
+obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o
 obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
 obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o
+obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o
 obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o
 obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
index b607a92..1ed3b98 100644 (file)
@@ -436,7 +436,7 @@ static int iommu_init_device(struct device *dev)
         * invalid address), we ignore the capability for the device so
         * it'll be forced to go into translation mode.
         */
-       if ((iommu_pass_through || !amd_iommu_force_isolation) &&
+       if ((iommu_default_passthrough() || !amd_iommu_force_isolation) &&
            dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
                struct amd_iommu *iommu;
 
@@ -1143,6 +1143,17 @@ static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
        iommu_completion_wait(iommu);
 }
 
+static void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id)
+{
+       struct iommu_cmd cmd;
+
+       build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
+                             dom_id, 1);
+       iommu_queue_command(iommu, &cmd);
+
+       iommu_completion_wait(iommu);
+}
+
 static void amd_iommu_flush_all(struct amd_iommu *iommu)
 {
        struct iommu_cmd cmd;
@@ -1424,18 +1435,21 @@ static void free_pagetable(struct protection_domain *domain)
  * another level increases the size of the address space by 9 bits to a size up
  * to 64 bits.
  */
-static bool increase_address_space(struct protection_domain *domain,
+static void increase_address_space(struct protection_domain *domain,
                                   gfp_t gfp)
 {
+       unsigned long flags;
        u64 *pte;
 
-       if (domain->mode == PAGE_MODE_6_LEVEL)
+       spin_lock_irqsave(&domain->lock, flags);
+
+       if (WARN_ON_ONCE(domain->mode == PAGE_MODE_6_LEVEL))
                /* address space already 64 bit large */
-               return false;
+               goto out;
 
        pte = (void *)get_zeroed_page(gfp);
        if (!pte)
-               return false;
+               goto out;
 
        *pte             = PM_LEVEL_PDE(domain->mode,
                                        iommu_virt_to_phys(domain->pt_root));
@@ -1443,7 +1457,10 @@ static bool increase_address_space(struct protection_domain *domain,
        domain->mode    += 1;
        domain->updated  = true;
 
-       return true;
+out:
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+       return;
 }
 
 static u64 *alloc_pte(struct protection_domain *domain,
@@ -1873,6 +1890,7 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain,
 {
        u64 pte_root = 0;
        u64 flags = 0;
+       u32 old_domid;
 
        if (domain->mode != PAGE_MODE_NONE)
                pte_root = iommu_virt_to_phys(domain->pt_root);
@@ -1922,8 +1940,20 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain,
        flags &= ~DEV_DOMID_MASK;
        flags |= domain->id;
 
+       old_domid = amd_iommu_dev_table[devid].data[1] & DEV_DOMID_MASK;
        amd_iommu_dev_table[devid].data[1]  = flags;
        amd_iommu_dev_table[devid].data[0]  = pte_root;
+
+       /*
+        * A kdump kernel might be replacing a domain ID that was copied from
+        * the previous kernel--if so, it needs to flush the translation cache
+        * entries for the old domain ID that is being overwritten
+        */
+       if (old_domid) {
+               struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+
+               amd_iommu_flush_tlb_domid(iommu, old_domid);
+       }
 }
 
 static void clear_dte_entry(u16 devid)
@@ -2226,7 +2256,7 @@ static int amd_iommu_add_device(struct device *dev)
 
        BUG_ON(!dev_data);
 
-       if (iommu_pass_through || dev_data->iommu_v2)
+       if (dev_data->iommu_v2)
                iommu_request_dm_for_dev(dev);
 
        /* Domains are initialized for this device - have a look what we ended up with */
@@ -2547,7 +2577,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
 
                        bus_addr  = address + s->dma_address + (j << PAGE_SHIFT);
                        phys_addr = (sg_phys(s) & PAGE_MASK) + (j << PAGE_SHIFT);
-                       ret = iommu_map_page(domain, bus_addr, phys_addr, PAGE_SIZE, prot, GFP_ATOMIC);
+                       ret = iommu_map_page(domain, bus_addr, phys_addr,
+                                            PAGE_SIZE, prot,
+                                            GFP_ATOMIC | __GFP_NOWARN);
                        if (ret)
                                goto out_unmap;
 
@@ -2805,7 +2837,7 @@ int __init amd_iommu_init_api(void)
 
 int __init amd_iommu_init_dma_ops(void)
 {
-       swiotlb        = (iommu_pass_through || sme_me_mask) ? 1 : 0;
+       swiotlb        = (iommu_default_passthrough() || sme_me_mask) ? 1 : 0;
        iommu_detected = 1;
 
        if (amd_iommu_unmap_flush)
@@ -3055,7 +3087,8 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
 }
 
 static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
-                          size_t page_size)
+                             size_t page_size,
+                             struct iommu_iotlb_gather *gather)
 {
        struct protection_domain *domain = to_pdomain(dom);
        size_t unmap_size;
@@ -3196,9 +3229,10 @@ static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain)
        domain_flush_complete(dom);
 }
 
-static void amd_iommu_iotlb_range_add(struct iommu_domain *domain,
-                                     unsigned long iova, size_t size)
+static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
+                                struct iommu_iotlb_gather *gather)
 {
+       amd_iommu_flush_iotlb_all(domain);
 }
 
 const struct iommu_ops amd_iommu_ops = {
@@ -3219,8 +3253,7 @@ const struct iommu_ops amd_iommu_ops = {
        .is_attach_deferred = amd_iommu_is_attach_deferred,
        .pgsize_bitmap  = AMD_IOMMU_PGSIZES,
        .flush_iotlb_all = amd_iommu_flush_iotlb_all,
-       .iotlb_range_add = amd_iommu_iotlb_range_add,
-       .iotlb_sync = amd_iommu_flush_iotlb_all,
+       .iotlb_sync = amd_iommu_iotlb_sync,
 };
 
 /*****************************************************************************
@@ -4313,13 +4346,62 @@ static const struct irq_domain_ops amd_ir_domain_ops = {
        .deactivate = irq_remapping_deactivate,
 };
 
+int amd_iommu_activate_guest_mode(void *data)
+{
+       struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
+       struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
+
+       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
+           !entry || entry->lo.fields_vapic.guest_mode)
+               return 0;
+
+       entry->lo.val = 0;
+       entry->hi.val = 0;
+
+       entry->lo.fields_vapic.guest_mode  = 1;
+       entry->lo.fields_vapic.ga_log_intr = 1;
+       entry->hi.fields.ga_root_ptr       = ir_data->ga_root_ptr;
+       entry->hi.fields.vector            = ir_data->ga_vector;
+       entry->lo.fields_vapic.ga_tag      = ir_data->ga_tag;
+
+       return modify_irte_ga(ir_data->irq_2_irte.devid,
+                             ir_data->irq_2_irte.index, entry, NULL);
+}
+EXPORT_SYMBOL(amd_iommu_activate_guest_mode);
+
+int amd_iommu_deactivate_guest_mode(void *data)
+{
+       struct amd_ir_data *ir_data = (struct amd_ir_data *)data;
+       struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
+       struct irq_cfg *cfg = ir_data->cfg;
+
+       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
+           !entry || !entry->lo.fields_vapic.guest_mode)
+               return 0;
+
+       entry->lo.val = 0;
+       entry->hi.val = 0;
+
+       entry->lo.fields_remap.dm          = apic->irq_dest_mode;
+       entry->lo.fields_remap.int_type    = apic->irq_delivery_mode;
+       entry->hi.fields.vector            = cfg->vector;
+       entry->lo.fields_remap.destination =
+                               APICID_TO_IRTE_DEST_LO(cfg->dest_apicid);
+       entry->hi.fields.destination =
+                               APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
+
+       return modify_irte_ga(ir_data->irq_2_irte.devid,
+                             ir_data->irq_2_irte.index, entry, NULL);
+}
+EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
+
 static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
 {
+       int ret;
        struct amd_iommu *iommu;
        struct amd_iommu_pi_data *pi_data = vcpu_info;
        struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
        struct amd_ir_data *ir_data = data->chip_data;
-       struct irte_ga *irte = (struct irte_ga *) ir_data->entry;
        struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
        struct iommu_dev_data *dev_data = search_dev_data(irte_info->devid);
 
@@ -4330,6 +4412,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
        if (!dev_data || !dev_data->use_vapic)
                return 0;
 
+       ir_data->cfg = irqd_cfg(data);
        pi_data->ir_data = ir_data;
 
        /* Note:
@@ -4348,37 +4431,24 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
 
        pi_data->prev_ga_tag = ir_data->cached_ga_tag;
        if (pi_data->is_guest_mode) {
-               /* Setting */
-               irte->hi.fields.ga_root_ptr = (pi_data->base >> 12);
-               irte->hi.fields.vector = vcpu_pi_info->vector;
-               irte->lo.fields_vapic.ga_log_intr = 1;
-               irte->lo.fields_vapic.guest_mode = 1;
-               irte->lo.fields_vapic.ga_tag = pi_data->ga_tag;
-
-               ir_data->cached_ga_tag = pi_data->ga_tag;
+               ir_data->ga_root_ptr = (pi_data->base >> 12);
+               ir_data->ga_vector = vcpu_pi_info->vector;
+               ir_data->ga_tag = pi_data->ga_tag;
+               ret = amd_iommu_activate_guest_mode(ir_data);
+               if (!ret)
+                       ir_data->cached_ga_tag = pi_data->ga_tag;
        } else {
-               /* Un-Setting */
-               struct irq_cfg *cfg = irqd_cfg(data);
-
-               irte->hi.val = 0;
-               irte->lo.val = 0;
-               irte->hi.fields.vector = cfg->vector;
-               irte->lo.fields_remap.guest_mode = 0;
-               irte->lo.fields_remap.destination =
-                               APICID_TO_IRTE_DEST_LO(cfg->dest_apicid);
-               irte->hi.fields.destination =
-                               APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
-               irte->lo.fields_remap.int_type = apic->irq_delivery_mode;
-               irte->lo.fields_remap.dm = apic->irq_dest_mode;
+               ret = amd_iommu_deactivate_guest_mode(ir_data);
 
                /*
                 * This communicates the ga_tag back to the caller
                 * so that it can do all the necessary clean up.
                 */
-               ir_data->cached_ga_tag = 0;
+               if (!ret)
+                       ir_data->cached_ga_tag = 0;
        }
 
-       return modify_irte_ga(irte_info->devid, irte_info->index, irte, ir_data);
+       return ret;
 }
 
 
diff --git a/drivers/iommu/amd_iommu.h b/drivers/iommu/amd_iommu.h
new file mode 100644 (file)
index 0000000..12d540d
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef AMD_IOMMU_H
+#define AMD_IOMMU_H
+
+int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line);
+
+#ifdef CONFIG_DMI
+void amd_iommu_apply_ivrs_quirks(void);
+#else
+static void amd_iommu_apply_ivrs_quirks(void) { }
+#endif
+
+#endif
index 4413aa6..568c523 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/irq_remapping.h>
 
 #include <linux/crash_dump.h>
+#include "amd_iommu.h"
 #include "amd_iommu_proto.h"
 #include "amd_iommu_types.h"
 #include "irq_remapping.h"
@@ -1002,7 +1003,7 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu,
        set_iommu_for_device(iommu, devid);
 }
 
-static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
+int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
 {
        struct devid_map *entry;
        struct list_head *list;
@@ -1153,6 +1154,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
        if (ret)
                return ret;
 
+       amd_iommu_apply_ivrs_quirks();
+
        /*
         * First save the recommended feature enable bits from ACPI
         */
diff --git a/drivers/iommu/amd_iommu_quirks.c b/drivers/iommu/amd_iommu_quirks.c
new file mode 100644 (file)
index 0000000..c235f79
--- /dev/null
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Quirks for AMD IOMMU
+ *
+ * Copyright (C) 2019 Kai-Heng Feng <kai.heng.feng@canonical.com>
+ */
+
+#ifdef CONFIG_DMI
+#include <linux/dmi.h>
+
+#include "amd_iommu.h"
+
+#define IVHD_SPECIAL_IOAPIC            1
+
+struct ivrs_quirk_entry {
+       u8 id;
+       u16 devid;
+};
+
+enum {
+       DELL_INSPIRON_7375 = 0,
+       DELL_LATITUDE_5495,
+       LENOVO_IDEAPAD_330S_15ARR,
+};
+
+static const struct ivrs_quirk_entry ivrs_ioapic_quirks[][3] __initconst = {
+       /* ivrs_ioapic[4]=00:14.0 ivrs_ioapic[5]=00:00.2 */
+       [DELL_INSPIRON_7375] = {
+               { .id = 4, .devid = 0xa0 },
+               { .id = 5, .devid = 0x2 },
+               {}
+       },
+       /* ivrs_ioapic[4]=00:14.0 */
+       [DELL_LATITUDE_5495] = {
+               { .id = 4, .devid = 0xa0 },
+               {}
+       },
+       /* ivrs_ioapic[32]=00:14.0 */
+       [LENOVO_IDEAPAD_330S_15ARR] = {
+               { .id = 32, .devid = 0xa0 },
+               {}
+       },
+       {}
+};
+
+static int __init ivrs_ioapic_quirk_cb(const struct dmi_system_id *d)
+{
+       const struct ivrs_quirk_entry *i;
+
+       for (i = d->driver_data; i->id != 0 && i->devid != 0; i++)
+               add_special_device(IVHD_SPECIAL_IOAPIC, i->id, (u16 *)&i->devid, 0);
+
+       return 0;
+}
+
+static const struct dmi_system_id ivrs_quirks[] __initconst = {
+       {
+               .callback = ivrs_ioapic_quirk_cb,
+               .ident = "Dell Inspiron 7375",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7375"),
+               },
+               .driver_data = (void *)&ivrs_ioapic_quirks[DELL_INSPIRON_7375],
+       },
+       {
+               .callback = ivrs_ioapic_quirk_cb,
+               .ident = "Dell Latitude 5495",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 5495"),
+               },
+               .driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495],
+       },
+       {
+               .callback = ivrs_ioapic_quirk_cb,
+               .ident = "Lenovo ideapad 330S-15ARR",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "81FB"),
+               },
+               .driver_data = (void *)&ivrs_ioapic_quirks[LENOVO_IDEAPAD_330S_15ARR],
+       },
+       {}
+};
+
+void __init amd_iommu_apply_ivrs_quirks(void)
+{
+       dmi_check_system(ivrs_quirks);
+}
+#endif
index 64edd5a..9ac229e 100644 (file)
@@ -873,6 +873,15 @@ struct amd_ir_data {
        struct msi_msg msi_entry;
        void *entry;    /* Pointer to union irte or struct irte_ga */
        void *ref;      /* Pointer to the actual irte */
+
+       /**
+        * Store information for activate/de-activate
+        * Guest virtual APIC mode during runtime.
+        */
+       struct irq_cfg *cfg;
+       int ga_vector;
+       int ga_root_ptr;
+       int ga_tag;
 };
 
 struct amd_irte_ops {
diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c
new file mode 100644 (file)
index 0000000..5c87a38
--- /dev/null
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Miscellaneous Arm SMMU implementation and integration quirks
+// Copyright (C) 2019 Arm Limited
+
+#define pr_fmt(fmt) "arm-smmu: " fmt
+
+#include <linux/bitfield.h>
+#include <linux/of.h>
+
+#include "arm-smmu.h"
+
+
+static int arm_smmu_gr0_ns(int offset)
+{
+       switch(offset) {
+       case ARM_SMMU_GR0_sCR0:
+       case ARM_SMMU_GR0_sACR:
+       case ARM_SMMU_GR0_sGFSR:
+       case ARM_SMMU_GR0_sGFSYNR0:
+       case ARM_SMMU_GR0_sGFSYNR1:
+       case ARM_SMMU_GR0_sGFSYNR2:
+               return offset + 0x400;
+       default:
+               return offset;
+       }
+}
+
+static u32 arm_smmu_read_ns(struct arm_smmu_device *smmu, int page,
+                           int offset)
+{
+       if (page == ARM_SMMU_GR0)
+               offset = arm_smmu_gr0_ns(offset);
+       return readl_relaxed(arm_smmu_page(smmu, page) + offset);
+}
+
+static void arm_smmu_write_ns(struct arm_smmu_device *smmu, int page,
+                             int offset, u32 val)
+{
+       if (page == ARM_SMMU_GR0)
+               offset = arm_smmu_gr0_ns(offset);
+       writel_relaxed(val, arm_smmu_page(smmu, page) + offset);
+}
+
+/* Since we don't care for sGFAR, we can do without 64-bit accessors */
+static const struct arm_smmu_impl calxeda_impl = {
+       .read_reg = arm_smmu_read_ns,
+       .write_reg = arm_smmu_write_ns,
+};
+
+
+struct cavium_smmu {
+       struct arm_smmu_device smmu;
+       u32 id_base;
+};
+
+static int cavium_cfg_probe(struct arm_smmu_device *smmu)
+{
+       static atomic_t context_count = ATOMIC_INIT(0);
+       struct cavium_smmu *cs = container_of(smmu, struct cavium_smmu, smmu);
+       /*
+        * Cavium CN88xx erratum #27704.
+        * Ensure ASID and VMID allocation is unique across all SMMUs in
+        * the system.
+        */
+       cs->id_base = atomic_fetch_add(smmu->num_context_banks, &context_count);
+       dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n");
+
+       return 0;
+}
+
+static int cavium_init_context(struct arm_smmu_domain *smmu_domain)
+{
+       struct cavium_smmu *cs = container_of(smmu_domain->smmu,
+                                             struct cavium_smmu, smmu);
+
+       if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2)
+               smmu_domain->cfg.vmid += cs->id_base;
+       else
+               smmu_domain->cfg.asid += cs->id_base;
+
+       return 0;
+}
+
+static const struct arm_smmu_impl cavium_impl = {
+       .cfg_probe = cavium_cfg_probe,
+       .init_context = cavium_init_context,
+};
+
+static struct arm_smmu_device *cavium_smmu_impl_init(struct arm_smmu_device *smmu)
+{
+       struct cavium_smmu *cs;
+
+       cs = devm_kzalloc(smmu->dev, sizeof(*cs), GFP_KERNEL);
+       if (!cs)
+               return ERR_PTR(-ENOMEM);
+
+       cs->smmu = *smmu;
+       cs->smmu.impl = &cavium_impl;
+
+       devm_kfree(smmu->dev, smmu);
+
+       return &cs->smmu;
+}
+
+
+#define ARM_MMU500_ACTLR_CPRE          (1 << 1)
+
+#define ARM_MMU500_ACR_CACHE_LOCK      (1 << 26)
+#define ARM_MMU500_ACR_S2CRB_TLBEN     (1 << 10)
+#define ARM_MMU500_ACR_SMTNMB_TLBEN    (1 << 8)
+
+static int arm_mmu500_reset(struct arm_smmu_device *smmu)
+{
+       u32 reg, major;
+       int i;
+       /*
+        * On MMU-500 r2p0 onwards we need to clear ACR.CACHE_LOCK before
+        * writes to the context bank ACTLRs will stick. And we just hope that
+        * Secure has also cleared SACR.CACHE_LOCK for this to take effect...
+        */
+       reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID7);
+       major = FIELD_GET(ID7_MAJOR, reg);
+       reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sACR);
+       if (major >= 2)
+               reg &= ~ARM_MMU500_ACR_CACHE_LOCK;
+       /*
+        * Allow unmatched Stream IDs to allocate bypass
+        * TLB entries for reduced latency.
+        */
+       reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN;
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sACR, reg);
+
+       /*
+        * Disable MMU-500's not-particularly-beneficial next-page
+        * prefetcher for the sake of errata #841119 and #826419.
+        */
+       for (i = 0; i < smmu->num_context_banks; ++i) {
+               reg = arm_smmu_cb_read(smmu, i, ARM_SMMU_CB_ACTLR);
+               reg &= ~ARM_MMU500_ACTLR_CPRE;
+               arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_ACTLR, reg);
+       }
+
+       return 0;
+}
+
+static const struct arm_smmu_impl arm_mmu500_impl = {
+       .reset = arm_mmu500_reset,
+};
+
+
+struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
+{
+       /*
+        * We will inevitably have to combine model-specific implementation
+        * quirks with platform-specific integration quirks, but everything
+        * we currently support happens to work out as straightforward
+        * mutually-exclusive assignments.
+        */
+       switch (smmu->model) {
+       case ARM_MMU500:
+               smmu->impl = &arm_mmu500_impl;
+               break;
+       case CAVIUM_SMMUV2:
+               return cavium_smmu_impl_init(smmu);
+       default:
+               break;
+       }
+
+       if (of_property_read_bool(smmu->dev->of_node,
+                                 "calxeda,smmu-secure-config-access"))
+               smmu->impl = &calxeda_impl;
+
+       return smmu;
+}
diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
deleted file mode 100644 (file)
index 1c278f7..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * IOMMU API for ARM architected SMMU implementations.
- *
- * Copyright (C) 2013 ARM Limited
- *
- * Author: Will Deacon <will.deacon@arm.com>
- */
-
-#ifndef _ARM_SMMU_REGS_H
-#define _ARM_SMMU_REGS_H
-
-/* Configuration registers */
-#define ARM_SMMU_GR0_sCR0              0x0
-#define sCR0_CLIENTPD                  (1 << 0)
-#define sCR0_GFRE                      (1 << 1)
-#define sCR0_GFIE                      (1 << 2)
-#define sCR0_EXIDENABLE                        (1 << 3)
-#define sCR0_GCFGFRE                   (1 << 4)
-#define sCR0_GCFGFIE                   (1 << 5)
-#define sCR0_USFCFG                    (1 << 10)
-#define sCR0_VMIDPNE                   (1 << 11)
-#define sCR0_PTM                       (1 << 12)
-#define sCR0_FB                                (1 << 13)
-#define sCR0_VMID16EN                  (1 << 31)
-#define sCR0_BSU_SHIFT                 14
-#define sCR0_BSU_MASK                  0x3
-
-/* Auxiliary Configuration register */
-#define ARM_SMMU_GR0_sACR              0x10
-
-/* Identification registers */
-#define ARM_SMMU_GR0_ID0               0x20
-#define ARM_SMMU_GR0_ID1               0x24
-#define ARM_SMMU_GR0_ID2               0x28
-#define ARM_SMMU_GR0_ID3               0x2c
-#define ARM_SMMU_GR0_ID4               0x30
-#define ARM_SMMU_GR0_ID5               0x34
-#define ARM_SMMU_GR0_ID6               0x38
-#define ARM_SMMU_GR0_ID7               0x3c
-#define ARM_SMMU_GR0_sGFSR             0x48
-#define ARM_SMMU_GR0_sGFSYNR0          0x50
-#define ARM_SMMU_GR0_sGFSYNR1          0x54
-#define ARM_SMMU_GR0_sGFSYNR2          0x58
-
-#define ID0_S1TS                       (1 << 30)
-#define ID0_S2TS                       (1 << 29)
-#define ID0_NTS                                (1 << 28)
-#define ID0_SMS                                (1 << 27)
-#define ID0_ATOSNS                     (1 << 26)
-#define ID0_PTFS_NO_AARCH32            (1 << 25)
-#define ID0_PTFS_NO_AARCH32S           (1 << 24)
-#define ID0_CTTW                       (1 << 14)
-#define ID0_NUMIRPT_SHIFT              16
-#define ID0_NUMIRPT_MASK               0xff
-#define ID0_NUMSIDB_SHIFT              9
-#define ID0_NUMSIDB_MASK               0xf
-#define ID0_EXIDS                      (1 << 8)
-#define ID0_NUMSMRG_SHIFT              0
-#define ID0_NUMSMRG_MASK               0xff
-
-#define ID1_PAGESIZE                   (1 << 31)
-#define ID1_NUMPAGENDXB_SHIFT          28
-#define ID1_NUMPAGENDXB_MASK           7
-#define ID1_NUMS2CB_SHIFT              16
-#define ID1_NUMS2CB_MASK               0xff
-#define ID1_NUMCB_SHIFT                        0
-#define ID1_NUMCB_MASK                 0xff
-
-#define ID2_OAS_SHIFT                  4
-#define ID2_OAS_MASK                   0xf
-#define ID2_IAS_SHIFT                  0
-#define ID2_IAS_MASK                   0xf
-#define ID2_UBS_SHIFT                  8
-#define ID2_UBS_MASK                   0xf
-#define ID2_PTFS_4K                    (1 << 12)
-#define ID2_PTFS_16K                   (1 << 13)
-#define ID2_PTFS_64K                   (1 << 14)
-#define ID2_VMID16                     (1 << 15)
-
-#define ID7_MAJOR_SHIFT                        4
-#define ID7_MAJOR_MASK                 0xf
-
-/* Global TLB invalidation */
-#define ARM_SMMU_GR0_TLBIVMID          0x64
-#define ARM_SMMU_GR0_TLBIALLNSNH       0x68
-#define ARM_SMMU_GR0_TLBIALLH          0x6c
-#define ARM_SMMU_GR0_sTLBGSYNC         0x70
-#define ARM_SMMU_GR0_sTLBGSTATUS       0x74
-#define sTLBGSTATUS_GSACTIVE           (1 << 0)
-
-/* Stream mapping registers */
-#define ARM_SMMU_GR0_SMR(n)            (0x800 + ((n) << 2))
-#define SMR_VALID                      (1 << 31)
-#define SMR_MASK_SHIFT                 16
-#define SMR_ID_SHIFT                   0
-
-#define ARM_SMMU_GR0_S2CR(n)           (0xc00 + ((n) << 2))
-#define S2CR_CBNDX_SHIFT               0
-#define S2CR_CBNDX_MASK                        0xff
-#define S2CR_EXIDVALID                 (1 << 10)
-#define S2CR_TYPE_SHIFT                        16
-#define S2CR_TYPE_MASK                 0x3
-enum arm_smmu_s2cr_type {
-       S2CR_TYPE_TRANS,
-       S2CR_TYPE_BYPASS,
-       S2CR_TYPE_FAULT,
-};
-
-#define S2CR_PRIVCFG_SHIFT             24
-#define S2CR_PRIVCFG_MASK              0x3
-enum arm_smmu_s2cr_privcfg {
-       S2CR_PRIVCFG_DEFAULT,
-       S2CR_PRIVCFG_DIPAN,
-       S2CR_PRIVCFG_UNPRIV,
-       S2CR_PRIVCFG_PRIV,
-};
-
-/* Context bank attribute registers */
-#define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
-#define CBAR_VMID_SHIFT                        0
-#define CBAR_VMID_MASK                 0xff
-#define CBAR_S1_BPSHCFG_SHIFT          8
-#define CBAR_S1_BPSHCFG_MASK           3
-#define CBAR_S1_BPSHCFG_NSH            3
-#define CBAR_S1_MEMATTR_SHIFT          12
-#define CBAR_S1_MEMATTR_MASK           0xf
-#define CBAR_S1_MEMATTR_WB             0xf
-#define CBAR_TYPE_SHIFT                        16
-#define CBAR_TYPE_MASK                 0x3
-#define CBAR_TYPE_S2_TRANS             (0 << CBAR_TYPE_SHIFT)
-#define CBAR_TYPE_S1_TRANS_S2_BYPASS   (1 << CBAR_TYPE_SHIFT)
-#define CBAR_TYPE_S1_TRANS_S2_FAULT    (2 << CBAR_TYPE_SHIFT)
-#define CBAR_TYPE_S1_TRANS_S2_TRANS    (3 << CBAR_TYPE_SHIFT)
-#define CBAR_IRPTNDX_SHIFT             24
-#define CBAR_IRPTNDX_MASK              0xff
-
-#define ARM_SMMU_GR1_CBFRSYNRA(n)      (0x400 + ((n) << 2))
-
-#define ARM_SMMU_GR1_CBA2R(n)          (0x800 + ((n) << 2))
-#define CBA2R_RW64_32BIT               (0 << 0)
-#define CBA2R_RW64_64BIT               (1 << 0)
-#define CBA2R_VMID_SHIFT               16
-#define CBA2R_VMID_MASK                        0xffff
-
-#define ARM_SMMU_CB_SCTLR              0x0
-#define ARM_SMMU_CB_ACTLR              0x4
-#define ARM_SMMU_CB_RESUME             0x8
-#define ARM_SMMU_CB_TTBCR2             0x10
-#define ARM_SMMU_CB_TTBR0              0x20
-#define ARM_SMMU_CB_TTBR1              0x28
-#define ARM_SMMU_CB_TTBCR              0x30
-#define ARM_SMMU_CB_CONTEXTIDR         0x34
-#define ARM_SMMU_CB_S1_MAIR0           0x38
-#define ARM_SMMU_CB_S1_MAIR1           0x3c
-#define ARM_SMMU_CB_PAR                        0x50
-#define ARM_SMMU_CB_FSR                        0x58
-#define ARM_SMMU_CB_FAR                        0x60
-#define ARM_SMMU_CB_FSYNR0             0x68
-#define ARM_SMMU_CB_S1_TLBIVA          0x600
-#define ARM_SMMU_CB_S1_TLBIASID                0x610
-#define ARM_SMMU_CB_S1_TLBIVAL         0x620
-#define ARM_SMMU_CB_S2_TLBIIPAS2       0x630
-#define ARM_SMMU_CB_S2_TLBIIPAS2L      0x638
-#define ARM_SMMU_CB_TLBSYNC            0x7f0
-#define ARM_SMMU_CB_TLBSTATUS          0x7f4
-#define ARM_SMMU_CB_ATS1PR             0x800
-#define ARM_SMMU_CB_ATSR               0x8f0
-
-#define SCTLR_S1_ASIDPNE               (1 << 12)
-#define SCTLR_CFCFG                    (1 << 7)
-#define SCTLR_CFIE                     (1 << 6)
-#define SCTLR_CFRE                     (1 << 5)
-#define SCTLR_E                                (1 << 4)
-#define SCTLR_AFE                      (1 << 2)
-#define SCTLR_TRE                      (1 << 1)
-#define SCTLR_M                                (1 << 0)
-
-#define CB_PAR_F                       (1 << 0)
-
-#define ATSR_ACTIVE                    (1 << 0)
-
-#define RESUME_RETRY                   (0 << 0)
-#define RESUME_TERMINATE               (1 << 0)
-
-#define TTBCR2_SEP_SHIFT               15
-#define TTBCR2_SEP_UPSTREAM            (0x7 << TTBCR2_SEP_SHIFT)
-#define TTBCR2_AS                      (1 << 4)
-
-#define TTBRn_ASID_SHIFT               48
-
-#define FSR_MULTI                      (1 << 31)
-#define FSR_SS                         (1 << 30)
-#define FSR_UUT                                (1 << 8)
-#define FSR_ASF                                (1 << 7)
-#define FSR_TLBLKF                     (1 << 6)
-#define FSR_TLBMCF                     (1 << 5)
-#define FSR_EF                         (1 << 4)
-#define FSR_PF                         (1 << 3)
-#define FSR_AFF                                (1 << 2)
-#define FSR_TF                         (1 << 1)
-
-#define FSR_IGN                                (FSR_AFF | FSR_ASF | \
-                                        FSR_TLBMCF | FSR_TLBLKF)
-#define FSR_FAULT                      (FSR_MULTI | FSR_SS | FSR_UUT | \
-                                        FSR_EF | FSR_PF | FSR_TF | FSR_IGN)
-
-#define FSYNR0_WNR                     (1 << 4)
-
-#endif /* _ARM_SMMU_REGS_H */
index a9a9fab..4aa4148 100644 (file)
 #define ARM_SMMU_MEMATTR_DEVICE_nGnRE  0x1
 #define ARM_SMMU_MEMATTR_OIWB          0xf
 
-#define Q_IDX(q, p)                    ((p) & ((1 << (q)->max_n_shift) - 1))
-#define Q_WRP(q, p)                    ((p) & (1 << (q)->max_n_shift))
-#define Q_OVERFLOW_FLAG                        (1 << 31)
-#define Q_OVF(q, p)                    ((p) & Q_OVERFLOW_FLAG)
+#define Q_IDX(llq, p)                  ((p) & ((1 << (llq)->max_n_shift) - 1))
+#define Q_WRP(llq, p)                  ((p) & (1 << (llq)->max_n_shift))
+#define Q_OVERFLOW_FLAG                        (1U << 31)
+#define Q_OVF(p)                       ((p) & Q_OVERFLOW_FLAG)
 #define Q_ENT(q, p)                    ((q)->base +                    \
-                                        Q_IDX(q, p) * (q)->ent_dwords)
+                                        Q_IDX(&((q)->llq), p) *        \
+                                        (q)->ent_dwords)
 
 #define Q_BASE_RWA                     (1UL << 62)
 #define Q_BASE_ADDR_MASK               GENMASK_ULL(51, 5)
 #define CMDQ_ERR_CERROR_ABT_IDX                2
 #define CMDQ_ERR_CERROR_ATC_INV_IDX    3
 
+#define CMDQ_PROD_OWNED_FLAG           Q_OVERFLOW_FLAG
+
+/*
+ * This is used to size the command queue and therefore must be at least
+ * BITS_PER_LONG so that the valid_map works correctly (it relies on the
+ * total number of queue entries being a multiple of BITS_PER_LONG).
+ */
+#define CMDQ_BATCH_ENTRIES             BITS_PER_LONG
+
 #define CMDQ_0_OP                      GENMASK_ULL(7, 0)
 #define CMDQ_0_SSV                     (1UL << 11)
 
 #define PRIQ_1_ADDR_MASK               GENMASK_ULL(63, 12)
 
 /* High-level queue structures */
-#define ARM_SMMU_POLL_TIMEOUT_US       100
-#define ARM_SMMU_CMDQ_SYNC_TIMEOUT_US  1000000 /* 1s! */
-#define ARM_SMMU_CMDQ_SYNC_SPIN_COUNT  10
+#define ARM_SMMU_POLL_TIMEOUT_US       1000000 /* 1s! */
+#define ARM_SMMU_POLL_SPIN_COUNT       10
 
 #define MSI_IOVA_BASE                  0x8000000
 #define MSI_IOVA_LENGTH                        0x100000
@@ -472,13 +481,29 @@ struct arm_smmu_cmdq_ent {
 
                #define CMDQ_OP_CMD_SYNC        0x46
                struct {
-                       u32                     msidata;
                        u64                     msiaddr;
                } sync;
        };
 };
 
+struct arm_smmu_ll_queue {
+       union {
+               u64                     val;
+               struct {
+                       u32             prod;
+                       u32             cons;
+               };
+               struct {
+                       atomic_t        prod;
+                       atomic_t        cons;
+               } atomic;
+               u8                      __pad[SMP_CACHE_BYTES];
+       } ____cacheline_aligned_in_smp;
+       u32                             max_n_shift;
+};
+
 struct arm_smmu_queue {
+       struct arm_smmu_ll_queue        llq;
        int                             irq; /* Wired interrupt */
 
        __le64                          *base;
@@ -486,17 +511,23 @@ struct arm_smmu_queue {
        u64                             q_base;
 
        size_t                          ent_dwords;
-       u32                             max_n_shift;
-       u32                             prod;
-       u32                             cons;
 
        u32 __iomem                     *prod_reg;
        u32 __iomem                     *cons_reg;
 };
 
+struct arm_smmu_queue_poll {
+       ktime_t                         timeout;
+       unsigned int                    delay;
+       unsigned int                    spin_cnt;
+       bool                            wfe;
+};
+
 struct arm_smmu_cmdq {
        struct arm_smmu_queue           q;
-       spinlock_t                      lock;
+       atomic_long_t                   *valid_map;
+       atomic_t                        owner_prod;
+       atomic_t                        lock;
 };
 
 struct arm_smmu_evtq {
@@ -576,8 +607,6 @@ struct arm_smmu_device {
 
        int                             gerr_irq;
        int                             combined_irq;
-       u32                             sync_nr;
-       u8                              prev_cmd_opcode;
 
        unsigned long                   ias; /* IPA */
        unsigned long                   oas; /* PA */
@@ -596,12 +625,6 @@ struct arm_smmu_device {
 
        struct arm_smmu_strtab_cfg      strtab_cfg;
 
-       /* Hi16xx adds an extra 32 bits of goodness to its MSI payload */
-       union {
-               u32                     sync_count;
-               u64                     padding;
-       };
-
        /* IOMMU core code handle */
        struct iommu_device             iommu;
 };
@@ -614,7 +637,7 @@ struct arm_smmu_master {
        struct list_head                domain_head;
        u32                             *sids;
        unsigned int                    num_sids;
-       bool                            ats_enabled             :1;
+       bool                            ats_enabled;
 };
 
 /* SMMU private data for an IOMMU domain */
@@ -631,6 +654,7 @@ struct arm_smmu_domain {
 
        struct io_pgtable_ops           *pgtbl_ops;
        bool                            non_strict;
+       atomic_t                        nr_ats_masters;
 
        enum arm_smmu_domain_stage      stage;
        union {
@@ -685,85 +709,97 @@ static void parse_driver_options(struct arm_smmu_device *smmu)
 }
 
 /* Low-level queue manipulation functions */
-static bool queue_full(struct arm_smmu_queue *q)
+static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
+{
+       u32 space, prod, cons;
+
+       prod = Q_IDX(q, q->prod);
+       cons = Q_IDX(q, q->cons);
+
+       if (Q_WRP(q, q->prod) == Q_WRP(q, q->cons))
+               space = (1 << q->max_n_shift) - (prod - cons);
+       else
+               space = cons - prod;
+
+       return space >= n;
+}
+
+static bool queue_full(struct arm_smmu_ll_queue *q)
 {
        return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
               Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
 }
 
-static bool queue_empty(struct arm_smmu_queue *q)
+static bool queue_empty(struct arm_smmu_ll_queue *q)
 {
        return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
               Q_WRP(q, q->prod) == Q_WRP(q, q->cons);
 }
 
-static void queue_sync_cons(struct arm_smmu_queue *q)
+static bool queue_consumed(struct arm_smmu_ll_queue *q, u32 prod)
 {
-       q->cons = readl_relaxed(q->cons_reg);
+       return ((Q_WRP(q, q->cons) == Q_WRP(q, prod)) &&
+               (Q_IDX(q, q->cons) > Q_IDX(q, prod))) ||
+              ((Q_WRP(q, q->cons) != Q_WRP(q, prod)) &&
+               (Q_IDX(q, q->cons) <= Q_IDX(q, prod)));
 }
 
-static void queue_inc_cons(struct arm_smmu_queue *q)
+static void queue_sync_cons_out(struct arm_smmu_queue *q)
 {
-       u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
-
-       q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
-
        /*
         * Ensure that all CPU accesses (reads and writes) to the queue
         * are complete before we update the cons pointer.
         */
        mb();
-       writel_relaxed(q->cons, q->cons_reg);
+       writel_relaxed(q->llq.cons, q->cons_reg);
+}
+
+static void queue_inc_cons(struct arm_smmu_ll_queue *q)
+{
+       u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
+       q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
 }
 
-static int queue_sync_prod(struct arm_smmu_queue *q)
+static int queue_sync_prod_in(struct arm_smmu_queue *q)
 {
        int ret = 0;
        u32 prod = readl_relaxed(q->prod_reg);
 
-       if (Q_OVF(q, prod) != Q_OVF(q, q->prod))
+       if (Q_OVF(prod) != Q_OVF(q->llq.prod))
                ret = -EOVERFLOW;
 
-       q->prod = prod;
+       q->llq.prod = prod;
        return ret;
 }
 
-static void queue_inc_prod(struct arm_smmu_queue *q)
+static u32 queue_inc_prod_n(struct arm_smmu_ll_queue *q, int n)
 {
-       u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + 1;
-
-       q->prod = Q_OVF(q, q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
-       writel(q->prod, q->prod_reg);
+       u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + n;
+       return Q_OVF(q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
 }
 
-/*
- * Wait for the SMMU to consume items. If sync is true, wait until the queue
- * is empty. Otherwise, wait until there is at least one free slot.
- */
-static int queue_poll_cons(struct arm_smmu_queue *q, bool sync, bool wfe)
+static void queue_poll_init(struct arm_smmu_device *smmu,
+                           struct arm_smmu_queue_poll *qp)
 {
-       ktime_t timeout;
-       unsigned int delay = 1, spin_cnt = 0;
-
-       /* Wait longer if it's a CMD_SYNC */
-       timeout = ktime_add_us(ktime_get(), sync ?
-                                           ARM_SMMU_CMDQ_SYNC_TIMEOUT_US :
-                                           ARM_SMMU_POLL_TIMEOUT_US);
+       qp->delay = 1;
+       qp->spin_cnt = 0;
+       qp->wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
+       qp->timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
+}
 
-       while (queue_sync_cons(q), (sync ? !queue_empty(q) : queue_full(q))) {
-               if (ktime_compare(ktime_get(), timeout) > 0)
-                       return -ETIMEDOUT;
+static int queue_poll(struct arm_smmu_queue_poll *qp)
+{
+       if (ktime_compare(ktime_get(), qp->timeout) > 0)
+               return -ETIMEDOUT;
 
-               if (wfe) {
-                       wfe();
-               } else if (++spin_cnt < ARM_SMMU_CMDQ_SYNC_SPIN_COUNT) {
-                       cpu_relax();
-                       continue;
-               } else {
-                       udelay(delay);
-                       delay *= 2;
-                       spin_cnt = 0;
-               }
+       if (qp->wfe) {
+               wfe();
+       } else if (++qp->spin_cnt < ARM_SMMU_POLL_SPIN_COUNT) {
+               cpu_relax();
+       } else {
+               udelay(qp->delay);
+               qp->delay *= 2;
+               qp->spin_cnt = 0;
        }
 
        return 0;
@@ -777,16 +813,6 @@ static void queue_write(__le64 *dst, u64 *src, size_t n_dwords)
                *dst++ = cpu_to_le64(*src++);
 }
 
-static int queue_insert_raw(struct arm_smmu_queue *q, u64 *ent)
-{
-       if (queue_full(q))
-               return -ENOSPC;
-
-       queue_write(Q_ENT(q, q->prod), ent, q->ent_dwords);
-       queue_inc_prod(q);
-       return 0;
-}
-
 static void queue_read(__le64 *dst, u64 *src, size_t n_dwords)
 {
        int i;
@@ -797,11 +823,12 @@ static void queue_read(__le64 *dst, u64 *src, size_t n_dwords)
 
 static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
 {
-       if (queue_empty(q))
+       if (queue_empty(&q->llq))
                return -EAGAIN;
 
-       queue_read(ent, Q_ENT(q, q->cons), q->ent_dwords);
-       queue_inc_cons(q);
+       queue_read(ent, Q_ENT(q, q->llq.cons), q->ent_dwords);
+       queue_inc_cons(&q->llq);
+       queue_sync_cons_out(q);
        return 0;
 }
 
@@ -868,20 +895,14 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
                cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp);
                break;
        case CMDQ_OP_CMD_SYNC:
-               if (ent->sync.msiaddr)
+               if (ent->sync.msiaddr) {
                        cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ);
-               else
+                       cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK;
+               } else {
                        cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
+               }
                cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
                cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
-               /*
-                * Commands are written little-endian, but we want the SMMU to
-                * receive MSIData, and thus write it back to memory, in CPU
-                * byte order, so big-endian needs an extra byteswap here.
-                */
-               cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIDATA,
-                                    cpu_to_le32(ent->sync.msidata));
-               cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK;
                break;
        default:
                return -ENOENT;
@@ -890,6 +911,27 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
        return 0;
 }
 
+static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
+                                        u32 prod)
+{
+       struct arm_smmu_queue *q = &smmu->cmdq.q;
+       struct arm_smmu_cmdq_ent ent = {
+               .opcode = CMDQ_OP_CMD_SYNC,
+       };
+
+       /*
+        * Beware that Hi16xx adds an extra 32 bits of goodness to its MSI
+        * payload, so the write will zero the entire command on that platform.
+        */
+       if (smmu->features & ARM_SMMU_FEAT_MSI &&
+           smmu->features & ARM_SMMU_FEAT_COHERENCY) {
+               ent.sync.msiaddr = q->base_dma + Q_IDX(&q->llq, prod) *
+                                  q->ent_dwords * 8;
+       }
+
+       arm_smmu_cmdq_build_cmd(cmd, &ent);
+}
+
 static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
 {
        static const char *cerror_str[] = {
@@ -948,109 +990,456 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
        queue_write(Q_ENT(q, cons), cmd, q->ent_dwords);
 }
 
-static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd)
+/*
+ * Command queue locking.
+ * This is a form of bastardised rwlock with the following major changes:
+ *
+ * - The only LOCK routines are exclusive_trylock() and shared_lock().
+ *   Neither have barrier semantics, and instead provide only a control
+ *   dependency.
+ *
+ * - The UNLOCK routines are supplemented with shared_tryunlock(), which
+ *   fails if the caller appears to be the last lock holder (yes, this is
+ *   racy). All successful UNLOCK routines have RELEASE semantics.
+ */
+static void arm_smmu_cmdq_shared_lock(struct arm_smmu_cmdq *cmdq)
 {
-       struct arm_smmu_queue *q = &smmu->cmdq.q;
-       bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
+       int val;
+
+       /*
+        * We can try to avoid the cmpxchg() loop by simply incrementing the
+        * lock counter. When held in exclusive state, the lock counter is set
+        * to INT_MIN so these increments won't hurt as the value will remain
+        * negative.
+        */
+       if (atomic_fetch_inc_relaxed(&cmdq->lock) >= 0)
+               return;
+
+       do {
+               val = atomic_cond_read_relaxed(&cmdq->lock, VAL >= 0);
+       } while (atomic_cmpxchg_relaxed(&cmdq->lock, val, val + 1) != val);
+}
+
+static void arm_smmu_cmdq_shared_unlock(struct arm_smmu_cmdq *cmdq)
+{
+       (void)atomic_dec_return_release(&cmdq->lock);
+}
 
-       smmu->prev_cmd_opcode = FIELD_GET(CMDQ_0_OP, cmd[0]);
+static bool arm_smmu_cmdq_shared_tryunlock(struct arm_smmu_cmdq *cmdq)
+{
+       if (atomic_read(&cmdq->lock) == 1)
+               return false;
 
-       while (queue_insert_raw(q, cmd) == -ENOSPC) {
-               if (queue_poll_cons(q, false, wfe))
-                       dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
+       arm_smmu_cmdq_shared_unlock(cmdq);
+       return true;
+}
+
+#define arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags)           \
+({                                                                     \
+       bool __ret;                                                     \
+       local_irq_save(flags);                                          \
+       __ret = !atomic_cmpxchg_relaxed(&cmdq->lock, 0, INT_MIN);       \
+       if (!__ret)                                                     \
+               local_irq_restore(flags);                               \
+       __ret;                                                          \
+})
+
+#define arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags)         \
+({                                                                     \
+       atomic_set_release(&cmdq->lock, 0);                             \
+       local_irq_restore(flags);                                       \
+})
+
+
+/*
+ * Command queue insertion.
+ * This is made fiddly by our attempts to achieve some sort of scalability
+ * since there is one queue shared amongst all of the CPUs in the system.  If
+ * you like mixed-size concurrency, dependency ordering and relaxed atomics,
+ * then you'll *love* this monstrosity.
+ *
+ * The basic idea is to split the queue up into ranges of commands that are
+ * owned by a given CPU; the owner may not have written all of the commands
+ * itself, but is responsible for advancing the hardware prod pointer when
+ * the time comes. The algorithm is roughly:
+ *
+ *     1. Allocate some space in the queue. At this point we also discover
+ *        whether the head of the queue is currently owned by another CPU,
+ *        or whether we are the owner.
+ *
+ *     2. Write our commands into our allocated slots in the queue.
+ *
+ *     3. Mark our slots as valid in arm_smmu_cmdq.valid_map.
+ *
+ *     4. If we are an owner:
+ *             a. Wait for the previous owner to finish.
+ *             b. Mark the queue head as unowned, which tells us the range
+ *                that we are responsible for publishing.
+ *             c. Wait for all commands in our owned range to become valid.
+ *             d. Advance the hardware prod pointer.
+ *             e. Tell the next owner we've finished.
+ *
+ *     5. If we are inserting a CMD_SYNC (we may or may not have been an
+ *        owner), then we need to stick around until it has completed:
+ *             a. If we have MSIs, the SMMU can write back into the CMD_SYNC
+ *                to clear the first 4 bytes.
+ *             b. Otherwise, we spin waiting for the hardware cons pointer to
+ *                advance past our command.
+ *
+ * The devil is in the details, particularly the use of locking for handling
+ * SYNC completion and freeing up space in the queue before we think that it is
+ * full.
+ */
+static void __arm_smmu_cmdq_poll_set_valid_map(struct arm_smmu_cmdq *cmdq,
+                                              u32 sprod, u32 eprod, bool set)
+{
+       u32 swidx, sbidx, ewidx, ebidx;
+       struct arm_smmu_ll_queue llq = {
+               .max_n_shift    = cmdq->q.llq.max_n_shift,
+               .prod           = sprod,
+       };
+
+       ewidx = BIT_WORD(Q_IDX(&llq, eprod));
+       ebidx = Q_IDX(&llq, eprod) % BITS_PER_LONG;
+
+       while (llq.prod != eprod) {
+               unsigned long mask;
+               atomic_long_t *ptr;
+               u32 limit = BITS_PER_LONG;
+
+               swidx = BIT_WORD(Q_IDX(&llq, llq.prod));
+               sbidx = Q_IDX(&llq, llq.prod) % BITS_PER_LONG;
+
+               ptr = &cmdq->valid_map[swidx];
+
+               if ((swidx == ewidx) && (sbidx < ebidx))
+                       limit = ebidx;
+
+               mask = GENMASK(limit - 1, sbidx);
+
+               /*
+                * The valid bit is the inverse of the wrap bit. This means
+                * that a zero-initialised queue is invalid and, after marking
+                * all entries as valid, they become invalid again when we
+                * wrap.
+                */
+               if (set) {
+                       atomic_long_xor(mask, ptr);
+               } else { /* Poll */
+                       unsigned long valid;
+
+                       valid = (ULONG_MAX + !!Q_WRP(&llq, llq.prod)) & mask;
+                       atomic_long_cond_read_relaxed(ptr, (VAL & mask) == valid);
+               }
+
+               llq.prod = queue_inc_prod_n(&llq, limit - sbidx);
        }
 }
 
-static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
-                                   struct arm_smmu_cmdq_ent *ent)
+/* Mark all entries in the range [sprod, eprod) as valid */
+static void arm_smmu_cmdq_set_valid_map(struct arm_smmu_cmdq *cmdq,
+                                       u32 sprod, u32 eprod)
+{
+       __arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, true);
+}
+
+/* Wait for all entries in the range [sprod, eprod) to become valid */
+static void arm_smmu_cmdq_poll_valid_map(struct arm_smmu_cmdq *cmdq,
+                                        u32 sprod, u32 eprod)
+{
+       __arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, false);
+}
+
+/* Wait for the command queue to become non-full */
+static int arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device *smmu,
+                                            struct arm_smmu_ll_queue *llq)
 {
-       u64 cmd[CMDQ_ENT_DWORDS];
        unsigned long flags;
+       struct arm_smmu_queue_poll qp;
+       struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
+       int ret = 0;
 
-       if (arm_smmu_cmdq_build_cmd(cmd, ent)) {
-               dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
-                        ent->opcode);
-               return;
+       /*
+        * Try to update our copy of cons by grabbing exclusive cmdq access. If
+        * that fails, spin until somebody else updates it for us.
+        */
+       if (arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags)) {
+               WRITE_ONCE(cmdq->q.llq.cons, readl_relaxed(cmdq->q.cons_reg));
+               arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags);
+               llq->val = READ_ONCE(cmdq->q.llq.val);
+               return 0;
        }
 
-       spin_lock_irqsave(&smmu->cmdq.lock, flags);
-       arm_smmu_cmdq_insert_cmd(smmu, cmd);
-       spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
+       queue_poll_init(smmu, &qp);
+       do {
+               llq->val = READ_ONCE(smmu->cmdq.q.llq.val);
+               if (!queue_full(llq))
+                       break;
+
+               ret = queue_poll(&qp);
+       } while (!ret);
+
+       return ret;
 }
 
 /*
- * The difference between val and sync_idx is bounded by the maximum size of
- * a queue at 2^20 entries, so 32 bits is plenty for wrap-safe arithmetic.
+ * Wait until the SMMU signals a CMD_SYNC completion MSI.
+ * Must be called with the cmdq lock held in some capacity.
  */
-static int __arm_smmu_sync_poll_msi(struct arm_smmu_device *smmu, u32 sync_idx)
+static int __arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device *smmu,
+                                         struct arm_smmu_ll_queue *llq)
 {
-       ktime_t timeout;
-       u32 val;
+       int ret = 0;
+       struct arm_smmu_queue_poll qp;
+       struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
+       u32 *cmd = (u32 *)(Q_ENT(&cmdq->q, llq->prod));
 
-       timeout = ktime_add_us(ktime_get(), ARM_SMMU_CMDQ_SYNC_TIMEOUT_US);
-       val = smp_cond_load_acquire(&smmu->sync_count,
-                                   (int)(VAL - sync_idx) >= 0 ||
-                                   !ktime_before(ktime_get(), timeout));
+       queue_poll_init(smmu, &qp);
 
-       return (int)(val - sync_idx) < 0 ? -ETIMEDOUT : 0;
+       /*
+        * The MSI won't generate an event, since it's being written back
+        * into the command queue.
+        */
+       qp.wfe = false;
+       smp_cond_load_relaxed(cmd, !VAL || (ret = queue_poll(&qp)));
+       llq->cons = ret ? llq->prod : queue_inc_prod_n(llq, 1);
+       return ret;
 }
 
-static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu)
+/*
+ * Wait until the SMMU cons index passes llq->prod.
+ * Must be called with the cmdq lock held in some capacity.
+ */
+static int __arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device *smmu,
+                                              struct arm_smmu_ll_queue *llq)
 {
-       u64 cmd[CMDQ_ENT_DWORDS];
-       unsigned long flags;
-       struct arm_smmu_cmdq_ent ent = {
-               .opcode = CMDQ_OP_CMD_SYNC,
-               .sync   = {
-                       .msiaddr = virt_to_phys(&smmu->sync_count),
-               },
-       };
+       struct arm_smmu_queue_poll qp;
+       struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
+       u32 prod = llq->prod;
+       int ret = 0;
+
+       queue_poll_init(smmu, &qp);
+       llq->val = READ_ONCE(smmu->cmdq.q.llq.val);
+       do {
+               if (queue_consumed(llq, prod))
+                       break;
 
-       spin_lock_irqsave(&smmu->cmdq.lock, flags);
+               ret = queue_poll(&qp);
 
-       /* Piggy-back on the previous command if it's a SYNC */
-       if (smmu->prev_cmd_opcode == CMDQ_OP_CMD_SYNC) {
-               ent.sync.msidata = smmu->sync_nr;
-       } else {
-               ent.sync.msidata = ++smmu->sync_nr;
-               arm_smmu_cmdq_build_cmd(cmd, &ent);
-               arm_smmu_cmdq_insert_cmd(smmu, cmd);
-       }
+               /*
+                * This needs to be a readl() so that our subsequent call
+                * to arm_smmu_cmdq_shared_tryunlock() can fail accurately.
+                *
+                * Specifically, we need to ensure that we observe all
+                * shared_lock()s by other CMD_SYNCs that share our owner,
+                * so that a failing call to tryunlock() means that we're
+                * the last one out and therefore we can safely advance
+                * cmdq->q.llq.cons. Roughly speaking:
+                *
+                * CPU 0                CPU1                    CPU2 (us)
+                *
+                * if (sync)
+                *      shared_lock();
+                *
+                * dma_wmb();
+                * set_valid_map();
+                *
+                *                      if (owner) {
+                *                              poll_valid_map();
+                *                              <control dependency>
+                *                              writel(prod_reg);
+                *
+                *                                              readl(cons_reg);
+                *                                              tryunlock();
+                *
+                * Requires us to see CPU 0's shared_lock() acquisition.
+                */
+               llq->cons = readl(cmdq->q.cons_reg);
+       } while (!ret);
 
-       spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
+       return ret;
+}
+
+static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu,
+                                        struct arm_smmu_ll_queue *llq)
+{
+       if (smmu->features & ARM_SMMU_FEAT_MSI &&
+           smmu->features & ARM_SMMU_FEAT_COHERENCY)
+               return __arm_smmu_cmdq_poll_until_msi(smmu, llq);
 
-       return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata);
+       return __arm_smmu_cmdq_poll_until_consumed(smmu, llq);
 }
 
-static int __arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
+static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds,
+                                       u32 prod, int n)
 {
-       u64 cmd[CMDQ_ENT_DWORDS];
+       int i;
+       struct arm_smmu_ll_queue llq = {
+               .max_n_shift    = cmdq->q.llq.max_n_shift,
+               .prod           = prod,
+       };
+
+       for (i = 0; i < n; ++i) {
+               u64 *cmd = &cmds[i * CMDQ_ENT_DWORDS];
+
+               prod = queue_inc_prod_n(&llq, i);
+               queue_write(Q_ENT(&cmdq->q, prod), cmd, CMDQ_ENT_DWORDS);
+       }
+}
+
+/*
+ * This is the actual insertion function, and provides the following
+ * ordering guarantees to callers:
+ *
+ * - There is a dma_wmb() before publishing any commands to the queue.
+ *   This can be relied upon to order prior writes to data structures
+ *   in memory (such as a CD or an STE) before the command.
+ *
+ * - On completion of a CMD_SYNC, there is a control dependency.
+ *   This can be relied upon to order subsequent writes to memory (e.g.
+ *   freeing an IOVA) after completion of the CMD_SYNC.
+ *
+ * - Command insertion is totally ordered, so if two CPUs each race to
+ *   insert their own list of commands then all of the commands from one
+ *   CPU will appear before any of the commands from the other CPU.
+ */
+static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
+                                      u64 *cmds, int n, bool sync)
+{
+       u64 cmd_sync[CMDQ_ENT_DWORDS];
+       u32 prod;
        unsigned long flags;
-       bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
-       struct arm_smmu_cmdq_ent ent = { .opcode = CMDQ_OP_CMD_SYNC };
-       int ret;
+       bool owner;
+       struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
+       struct arm_smmu_ll_queue llq = {
+               .max_n_shift = cmdq->q.llq.max_n_shift,
+       }, head = llq;
+       int ret = 0;
 
-       arm_smmu_cmdq_build_cmd(cmd, &ent);
+       /* 1. Allocate some space in the queue */
+       local_irq_save(flags);
+       llq.val = READ_ONCE(cmdq->q.llq.val);
+       do {
+               u64 old;
+
+               while (!queue_has_space(&llq, n + sync)) {
+                       local_irq_restore(flags);
+                       if (arm_smmu_cmdq_poll_until_not_full(smmu, &llq))
+                               dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
+                       local_irq_save(flags);
+               }
+
+               head.cons = llq.cons;
+               head.prod = queue_inc_prod_n(&llq, n + sync) |
+                                            CMDQ_PROD_OWNED_FLAG;
 
-       spin_lock_irqsave(&smmu->cmdq.lock, flags);
-       arm_smmu_cmdq_insert_cmd(smmu, cmd);
-       ret = queue_poll_cons(&smmu->cmdq.q, true, wfe);
-       spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
+               old = cmpxchg_relaxed(&cmdq->q.llq.val, llq.val, head.val);
+               if (old == llq.val)
+                       break;
+
+               llq.val = old;
+       } while (1);
+       owner = !(llq.prod & CMDQ_PROD_OWNED_FLAG);
+       head.prod &= ~CMDQ_PROD_OWNED_FLAG;
+       llq.prod &= ~CMDQ_PROD_OWNED_FLAG;
+
+       /*
+        * 2. Write our commands into the queue
+        * Dependency ordering from the cmpxchg() loop above.
+        */
+       arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n);
+       if (sync) {
+               prod = queue_inc_prod_n(&llq, n);
+               arm_smmu_cmdq_build_sync_cmd(cmd_sync, smmu, prod);
+               queue_write(Q_ENT(&cmdq->q, prod), cmd_sync, CMDQ_ENT_DWORDS);
+
+               /*
+                * In order to determine completion of our CMD_SYNC, we must
+                * ensure that the queue can't wrap twice without us noticing.
+                * We achieve that by taking the cmdq lock as shared before
+                * marking our slot as valid.
+                */
+               arm_smmu_cmdq_shared_lock(cmdq);
+       }
+
+       /* 3. Mark our slots as valid, ensuring commands are visible first */
+       dma_wmb();
+       arm_smmu_cmdq_set_valid_map(cmdq, llq.prod, head.prod);
+
+       /* 4. If we are the owner, take control of the SMMU hardware */
+       if (owner) {
+               /* a. Wait for previous owner to finish */
+               atomic_cond_read_relaxed(&cmdq->owner_prod, VAL == llq.prod);
+
+               /* b. Stop gathering work by clearing the owned flag */
+               prod = atomic_fetch_andnot_relaxed(CMDQ_PROD_OWNED_FLAG,
+                                                  &cmdq->q.llq.atomic.prod);
+               prod &= ~CMDQ_PROD_OWNED_FLAG;
+
+               /*
+                * c. Wait for any gathered work to be written to the queue.
+                * Note that we read our own entries so that we have the control
+                * dependency required by (d).
+                */
+               arm_smmu_cmdq_poll_valid_map(cmdq, llq.prod, prod);
+
+               /*
+                * d. Advance the hardware prod pointer
+                * Control dependency ordering from the entries becoming valid.
+                */
+               writel_relaxed(prod, cmdq->q.prod_reg);
+
+               /*
+                * e. Tell the next owner we're done
+                * Make sure we've updated the hardware first, so that we don't
+                * race to update prod and potentially move it backwards.
+                */
+               atomic_set_release(&cmdq->owner_prod, prod);
+       }
+
+       /* 5. If we are inserting a CMD_SYNC, we must wait for it to complete */
+       if (sync) {
+               llq.prod = queue_inc_prod_n(&llq, n);
+               ret = arm_smmu_cmdq_poll_until_sync(smmu, &llq);
+               if (ret) {
+                       dev_err_ratelimited(smmu->dev,
+                                           "CMD_SYNC timeout at 0x%08x [hwprod 0x%08x, hwcons 0x%08x]\n",
+                                           llq.prod,
+                                           readl_relaxed(cmdq->q.prod_reg),
+                                           readl_relaxed(cmdq->q.cons_reg));
+               }
+
+               /*
+                * Try to unlock the cmq lock. This will fail if we're the last
+                * reader, in which case we can safely update cmdq->q.llq.cons
+                */
+               if (!arm_smmu_cmdq_shared_tryunlock(cmdq)) {
+                       WRITE_ONCE(cmdq->q.llq.cons, llq.cons);
+                       arm_smmu_cmdq_shared_unlock(cmdq);
+               }
+       }
 
+       local_irq_restore(flags);
        return ret;
 }
 
-static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
+static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
+                                  struct arm_smmu_cmdq_ent *ent)
 {
-       int ret;
-       bool msi = (smmu->features & ARM_SMMU_FEAT_MSI) &&
-                  (smmu->features & ARM_SMMU_FEAT_COHERENCY);
+       u64 cmd[CMDQ_ENT_DWORDS];
 
-       ret = msi ? __arm_smmu_cmdq_issue_sync_msi(smmu)
-                 : __arm_smmu_cmdq_issue_sync(smmu);
-       if (ret)
-               dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
-       return ret;
+       if (arm_smmu_cmdq_build_cmd(cmd, ent)) {
+               dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
+                        ent->opcode);
+               return -EINVAL;
+       }
+
+       return arm_smmu_cmdq_issue_cmdlist(smmu, cmd, 1, false);
+}
+
+static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
+{
+       return arm_smmu_cmdq_issue_cmdlist(smmu, NULL, 0, true);
 }
 
 /* Context descriptor manipulation functions */
@@ -1186,8 +1575,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
                        ste_live = true;
                        break;
                case STRTAB_STE_0_CFG_ABORT:
-                       if (disable_bypass)
-                               break;
+                       BUG_ON(!disable_bypass);
+                       break;
                default:
                        BUG(); /* STE corruption */
                }
@@ -1305,6 +1694,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
        int i;
        struct arm_smmu_device *smmu = dev;
        struct arm_smmu_queue *q = &smmu->evtq.q;
+       struct arm_smmu_ll_queue *llq = &q->llq;
        u64 evt[EVTQ_ENT_DWORDS];
 
        do {
@@ -1322,12 +1712,13 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
                 * Not much we can do on overflow, so scream and pretend we're
                 * trying harder.
                 */
-               if (queue_sync_prod(q) == -EOVERFLOW)
+               if (queue_sync_prod_in(q) == -EOVERFLOW)
                        dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n");
-       } while (!queue_empty(q));
+       } while (!queue_empty(llq));
 
        /* Sync our overflow flag, as we believe we're up to speed */
-       q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
+       llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
+                   Q_IDX(llq, llq->cons);
        return IRQ_HANDLED;
 }
 
@@ -1373,19 +1764,21 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
 {
        struct arm_smmu_device *smmu = dev;
        struct arm_smmu_queue *q = &smmu->priq.q;
+       struct arm_smmu_ll_queue *llq = &q->llq;
        u64 evt[PRIQ_ENT_DWORDS];
 
        do {
                while (!queue_remove_raw(q, evt))
                        arm_smmu_handle_ppr(smmu, evt);
 
-               if (queue_sync_prod(q) == -EOVERFLOW)
+               if (queue_sync_prod_in(q) == -EOVERFLOW)
                        dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
-       } while (!queue_empty(q));
+       } while (!queue_empty(llq));
 
        /* Sync our overflow flag, as we believe we're up to speed */
-       q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
-       writel(q->cons, q->cons_reg);
+       llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
+                     Q_IDX(llq, llq->cons);
+       queue_sync_cons_out(q);
        return IRQ_HANDLED;
 }
 
@@ -1534,6 +1927,23 @@ static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
        if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
                return 0;
 
+       /*
+        * Ensure that we've completed prior invalidation of the main TLBs
+        * before we read 'nr_ats_masters' in case of a concurrent call to
+        * arm_smmu_enable_ats():
+        *
+        *      // unmap()                      // arm_smmu_enable_ats()
+        *      TLBI+SYNC                       atomic_inc(&nr_ats_masters);
+        *      smp_mb();                       [...]
+        *      atomic_read(&nr_ats_masters);   pci_enable_ats() // writel()
+        *
+        * Ensures that we always see the incremented 'nr_ats_masters' count if
+        * ATS was enabled at the PCI device before completion of the TLBI.
+        */
+       smp_mb();
+       if (!atomic_read(&smmu_domain->nr_ats_masters))
+               return 0;
+
        arm_smmu_atc_inv_to_cmd(ssid, iova, size, &cmd);
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
@@ -1545,13 +1955,6 @@ static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
 }
 
 /* IO_PGTABLE API */
-static void arm_smmu_tlb_sync(void *cookie)
-{
-       struct arm_smmu_domain *smmu_domain = cookie;
-
-       arm_smmu_cmdq_issue_sync(smmu_domain->smmu);
-}
-
 static void arm_smmu_tlb_inv_context(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
@@ -1570,25 +1973,32 @@ static void arm_smmu_tlb_inv_context(void *cookie)
        /*
         * NOTE: when io-pgtable is in non-strict mode, we may get here with
         * PTEs previously cleared by unmaps on the current CPU not yet visible
-        * to the SMMU. We are relying on the DSB implicit in queue_inc_prod()
-        * to guarantee those are observed before the TLBI. Do be careful, 007.
+        * to the SMMU. We are relying on the dma_wmb() implicit during cmd
+        * insertion to guarantee those are observed before the TLBI. Do be
+        * careful, 007.
         */
        arm_smmu_cmdq_issue_cmd(smmu, &cmd);
        arm_smmu_cmdq_issue_sync(smmu);
+       arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
 }
 
-static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
-                                         size_t granule, bool leaf, void *cookie)
+static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
+                                  size_t granule, bool leaf,
+                                  struct arm_smmu_domain *smmu_domain)
 {
-       struct arm_smmu_domain *smmu_domain = cookie;
+       u64 cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS];
        struct arm_smmu_device *smmu = smmu_domain->smmu;
+       unsigned long start = iova, end = iova + size;
+       int i = 0;
        struct arm_smmu_cmdq_ent cmd = {
                .tlbi = {
                        .leaf   = leaf,
-                       .addr   = iova,
                },
        };
 
+       if (!size)
+               return;
+
        if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
                cmd.opcode      = CMDQ_OP_TLBI_NH_VA;
                cmd.tlbi.asid   = smmu_domain->s1_cfg.cd.asid;
@@ -1597,16 +2007,54 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
                cmd.tlbi.vmid   = smmu_domain->s2_cfg.vmid;
        }
 
-       do {
-               arm_smmu_cmdq_issue_cmd(smmu, &cmd);
-               cmd.tlbi.addr += granule;
-       } while (size -= granule);
+       while (iova < end) {
+               if (i == CMDQ_BATCH_ENTRIES) {
+                       arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, false);
+                       i = 0;
+               }
+
+               cmd.tlbi.addr = iova;
+               arm_smmu_cmdq_build_cmd(&cmds[i * CMDQ_ENT_DWORDS], &cmd);
+               iova += granule;
+               i++;
+       }
+
+       arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, true);
+
+       /*
+        * Unfortunately, this can't be leaf-only since we may have
+        * zapped an entire table.
+        */
+       arm_smmu_atc_inv_domain(smmu_domain, 0, start, size);
+}
+
+static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
+                                        unsigned long iova, size_t granule,
+                                        void *cookie)
+{
+       struct arm_smmu_domain *smmu_domain = cookie;
+       struct iommu_domain *domain = &smmu_domain->domain;
+
+       iommu_iotlb_gather_add_page(domain, gather, iova, granule);
 }
 
-static const struct iommu_gather_ops arm_smmu_gather_ops = {
+static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
+                                 size_t granule, void *cookie)
+{
+       arm_smmu_tlb_inv_range(iova, size, granule, false, cookie);
+}
+
+static void arm_smmu_tlb_inv_leaf(unsigned long iova, size_t size,
+                                 size_t granule, void *cookie)
+{
+       arm_smmu_tlb_inv_range(iova, size, granule, true, cookie);
+}
+
+static const struct iommu_flush_ops arm_smmu_flush_ops = {
        .tlb_flush_all  = arm_smmu_tlb_inv_context,
-       .tlb_add_flush  = arm_smmu_tlb_inv_range_nosync,
-       .tlb_sync       = arm_smmu_tlb_sync,
+       .tlb_flush_walk = arm_smmu_tlb_inv_walk,
+       .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
+       .tlb_add_page   = arm_smmu_tlb_inv_page_nosync,
 };
 
 /* IOMMU API */
@@ -1796,7 +2244,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
                .ias            = ias,
                .oas            = oas,
                .coherent_walk  = smmu->features & ARM_SMMU_FEAT_COHERENCY,
-               .tlb            = &arm_smmu_gather_ops,
+               .tlb            = &arm_smmu_flush_ops,
                .iommu_dev      = smmu->dev,
        };
 
@@ -1863,44 +2311,65 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)
        }
 }
 
-static int arm_smmu_enable_ats(struct arm_smmu_master *master)
+#ifdef CONFIG_PCI_ATS
+static bool arm_smmu_ats_supported(struct arm_smmu_master *master)
 {
-       int ret;
-       size_t stu;
        struct pci_dev *pdev;
        struct arm_smmu_device *smmu = master->smmu;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
 
        if (!(smmu->features & ARM_SMMU_FEAT_ATS) || !dev_is_pci(master->dev) ||
            !(fwspec->flags & IOMMU_FWSPEC_PCI_RC_ATS) || pci_ats_disabled())
-               return -ENXIO;
+               return false;
 
        pdev = to_pci_dev(master->dev);
-       if (pdev->untrusted)
-               return -EPERM;
+       return !pdev->untrusted && pdev->ats_cap;
+}
+#else
+static bool arm_smmu_ats_supported(struct arm_smmu_master *master)
+{
+       return false;
+}
+#endif
+
+static void arm_smmu_enable_ats(struct arm_smmu_master *master)
+{
+       size_t stu;
+       struct pci_dev *pdev;
+       struct arm_smmu_device *smmu = master->smmu;
+       struct arm_smmu_domain *smmu_domain = master->domain;
+
+       /* Don't enable ATS at the endpoint if it's not enabled in the STE */
+       if (!master->ats_enabled)
+               return;
 
        /* Smallest Translation Unit: log2 of the smallest supported granule */
        stu = __ffs(smmu->pgsize_bitmap);
+       pdev = to_pci_dev(master->dev);
 
-       ret = pci_enable_ats(pdev, stu);
-       if (ret)
-               return ret;
-
-       master->ats_enabled = true;
-       return 0;
+       atomic_inc(&smmu_domain->nr_ats_masters);
+       arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
+       if (pci_enable_ats(pdev, stu))
+               dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu);
 }
 
 static void arm_smmu_disable_ats(struct arm_smmu_master *master)
 {
        struct arm_smmu_cmdq_ent cmd;
+       struct arm_smmu_domain *smmu_domain = master->domain;
 
-       if (!master->ats_enabled || !dev_is_pci(master->dev))
+       if (!master->ats_enabled)
                return;
 
+       pci_disable_ats(to_pci_dev(master->dev));
+       /*
+        * Ensure ATS is disabled at the endpoint before we issue the
+        * ATC invalidation via the SMMU.
+        */
+       wmb();
        arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
        arm_smmu_atc_inv_master(master, &cmd);
-       pci_disable_ats(to_pci_dev(master->dev));
-       master->ats_enabled = false;
+       atomic_dec(&smmu_domain->nr_ats_masters);
 }
 
 static void arm_smmu_detach_dev(struct arm_smmu_master *master)
@@ -1911,14 +2380,15 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
        if (!smmu_domain)
                return;
 
+       arm_smmu_disable_ats(master);
+
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
        list_del(&master->domain_head);
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
        master->domain = NULL;
+       master->ats_enabled = false;
        arm_smmu_install_ste_for_dev(master);
-
-       arm_smmu_disable_ats(master);
 }
 
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -1958,17 +2428,20 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 
        master->domain = smmu_domain;
 
-       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_add(&master->domain_head, &smmu_domain->devices);
-       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-
        if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS)
-               arm_smmu_enable_ats(master);
+               master->ats_enabled = arm_smmu_ats_supported(master);
 
        if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
                arm_smmu_write_ctx_desc(smmu, &smmu_domain->s1_cfg);
 
        arm_smmu_install_ste_for_dev(master);
+
+       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
+       list_add(&master->domain_head, &smmu_domain->devices);
+       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
+
+       arm_smmu_enable_ats(master);
+
 out_unlock:
        mutex_unlock(&smmu_domain->init_mutex);
        return ret;
@@ -1985,21 +2458,16 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
        return ops->map(ops, iova, paddr, size, prot);
 }
 
-static size_t
-arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
+static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+                            size_t size, struct iommu_iotlb_gather *gather)
 {
-       int ret;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
 
        if (!ops)
                return 0;
 
-       ret = ops->unmap(ops, iova, size);
-       if (ret && arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size))
-               return 0;
-
-       return ret;
+       return ops->unmap(ops, iova, size, gather);
 }
 
 static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
@@ -2010,12 +2478,13 @@ static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
                arm_smmu_tlb_inv_context(smmu_domain);
 }
 
-static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
+static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
+                               struct iommu_iotlb_gather *gather)
 {
-       struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 
-       if (smmu)
-               arm_smmu_cmdq_issue_sync(smmu);
+       arm_smmu_tlb_inv_range(gather->start, gather->end - gather->start,
+                              gather->pgsize, true, smmu_domain);
 }
 
 static phys_addr_t
@@ -2286,13 +2755,13 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
        size_t qsz;
 
        do {
-               qsz = ((1 << q->max_n_shift) * dwords) << 3;
+               qsz = ((1 << q->llq.max_n_shift) * dwords) << 3;
                q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma,
                                              GFP_KERNEL);
                if (q->base || qsz < PAGE_SIZE)
                        break;
 
-               q->max_n_shift--;
+               q->llq.max_n_shift--;
        } while (1);
 
        if (!q->base) {
@@ -2304,7 +2773,7 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
 
        if (!WARN_ON(q->base_dma & (qsz - 1))) {
                dev_info(smmu->dev, "allocated %u entries for %s\n",
-                        1 << q->max_n_shift, name);
+                        1 << q->llq.max_n_shift, name);
        }
 
        q->prod_reg     = arm_smmu_page1_fixup(prod_off, smmu);
@@ -2313,24 +2782,55 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
 
        q->q_base  = Q_BASE_RWA;
        q->q_base |= q->base_dma & Q_BASE_ADDR_MASK;
-       q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->max_n_shift);
+       q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->llq.max_n_shift);
 
-       q->prod = q->cons = 0;
+       q->llq.prod = q->llq.cons = 0;
        return 0;
 }
 
+static void arm_smmu_cmdq_free_bitmap(void *data)
+{
+       unsigned long *bitmap = data;
+       bitmap_free(bitmap);
+}
+
+static int arm_smmu_cmdq_init(struct arm_smmu_device *smmu)
+{
+       int ret = 0;
+       struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
+       unsigned int nents = 1 << cmdq->q.llq.max_n_shift;
+       atomic_long_t *bitmap;
+
+       atomic_set(&cmdq->owner_prod, 0);
+       atomic_set(&cmdq->lock, 0);
+
+       bitmap = (atomic_long_t *)bitmap_zalloc(nents, GFP_KERNEL);
+       if (!bitmap) {
+               dev_err(smmu->dev, "failed to allocate cmdq bitmap\n");
+               ret = -ENOMEM;
+       } else {
+               cmdq->valid_map = bitmap;
+               devm_add_action(smmu->dev, arm_smmu_cmdq_free_bitmap, bitmap);
+       }
+
+       return ret;
+}
+
 static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
 {
        int ret;
 
        /* cmdq */
-       spin_lock_init(&smmu->cmdq.lock);
        ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD,
                                      ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS,
                                      "cmdq");
        if (ret)
                return ret;
 
+       ret = arm_smmu_cmdq_init(smmu);
+       if (ret)
+               return ret;
+
        /* evtq */
        ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD,
                                      ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS,
@@ -2708,8 +3208,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 
        /* Command queue */
        writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);
-       writel_relaxed(smmu->cmdq.q.prod, smmu->base + ARM_SMMU_CMDQ_PROD);
-       writel_relaxed(smmu->cmdq.q.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
+       writel_relaxed(smmu->cmdq.q.llq.prod, smmu->base + ARM_SMMU_CMDQ_PROD);
+       writel_relaxed(smmu->cmdq.q.llq.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
 
        enables = CR0_CMDQEN;
        ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
@@ -2736,9 +3236,9 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 
        /* Event queue */
        writeq_relaxed(smmu->evtq.q.q_base, smmu->base + ARM_SMMU_EVTQ_BASE);
-       writel_relaxed(smmu->evtq.q.prod,
+       writel_relaxed(smmu->evtq.q.llq.prod,
                       arm_smmu_page1_fixup(ARM_SMMU_EVTQ_PROD, smmu));
-       writel_relaxed(smmu->evtq.q.cons,
+       writel_relaxed(smmu->evtq.q.llq.cons,
                       arm_smmu_page1_fixup(ARM_SMMU_EVTQ_CONS, smmu));
 
        enables |= CR0_EVTQEN;
@@ -2753,9 +3253,9 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
        if (smmu->features & ARM_SMMU_FEAT_PRI) {
                writeq_relaxed(smmu->priq.q.q_base,
                               smmu->base + ARM_SMMU_PRIQ_BASE);
-               writel_relaxed(smmu->priq.q.prod,
+               writel_relaxed(smmu->priq.q.llq.prod,
                               arm_smmu_page1_fixup(ARM_SMMU_PRIQ_PROD, smmu));
-               writel_relaxed(smmu->priq.q.cons,
+               writel_relaxed(smmu->priq.q.llq.cons,
                               arm_smmu_page1_fixup(ARM_SMMU_PRIQ_CONS, smmu));
 
                enables |= CR0_PRIQEN;
@@ -2909,18 +3409,24 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
        }
 
        /* Queue sizes, capped to ensure natural alignment */
-       smmu->cmdq.q.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT,
-                                        FIELD_GET(IDR1_CMDQS, reg));
-       if (!smmu->cmdq.q.max_n_shift) {
-               /* Odd alignment restrictions on the base, so ignore for now */
-               dev_err(smmu->dev, "unit-length command queue not supported\n");
+       smmu->cmdq.q.llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT,
+                                            FIELD_GET(IDR1_CMDQS, reg));
+       if (smmu->cmdq.q.llq.max_n_shift <= ilog2(CMDQ_BATCH_ENTRIES)) {
+               /*
+                * We don't support splitting up batches, so one batch of
+                * commands plus an extra sync needs to fit inside the command
+                * queue. There's also no way we can handle the weird alignment
+                * restrictions on the base pointer for a unit-length queue.
+                */
+               dev_err(smmu->dev, "command queue size <= %d entries not supported\n",
+                       CMDQ_BATCH_ENTRIES);
                return -ENXIO;
        }
 
-       smmu->evtq.q.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT,
-                                        FIELD_GET(IDR1_EVTQS, reg));
-       smmu->priq.q.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT,
-                                        FIELD_GET(IDR1_PRIQS, reg));
+       smmu->evtq.q.llq.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT,
+                                            FIELD_GET(IDR1_EVTQS, reg));
+       smmu->priq.q.llq.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT,
+                                            FIELD_GET(IDR1_PRIQS, reg));
 
        /* SID/SSID sizes */
        smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg);
index 64977c1..5b93c79 100644 (file)
 
 #include <linux/acpi.h>
 #include <linux/acpi_iort.h>
-#include <linux/atomic.h>
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/dma-iommu.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/io-64-nonatomic-hi-lo.h>
-#include <linux/io-pgtable.h>
-#include <linux/iommu.h>
 #include <linux/iopoll.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 
 #include <linux/amba/bus.h>
 #include <linux/fsl/mc.h>
 
-#include "arm-smmu-regs.h"
+#include "arm-smmu.h"
 
 /*
  * Apparently, some Qualcomm arm64 platforms which appear to expose their SMMU
  */
 #define QCOM_DUMMY_VAL -1
 
-#define ARM_MMU500_ACTLR_CPRE          (1 << 1)
-
-#define ARM_MMU500_ACR_CACHE_LOCK      (1 << 26)
-#define ARM_MMU500_ACR_S2CRB_TLBEN     (1 << 10)
-#define ARM_MMU500_ACR_SMTNMB_TLBEN    (1 << 8)
-
 #define TLB_LOOP_TIMEOUT               1000000 /* 1s! */
 #define TLB_SPIN_COUNT                 10
 
-/* Maximum number of context banks per SMMU */
-#define ARM_SMMU_MAX_CBS               128
-
-/* SMMU global address space */
-#define ARM_SMMU_GR0(smmu)             ((smmu)->base)
-#define ARM_SMMU_GR1(smmu)             ((smmu)->base + (1 << (smmu)->pgshift))
-
-/*
- * SMMU global address space with conditional offset to access secure
- * aliases of non-secure registers (e.g. nsCR0: 0x400, nsGFSR: 0x448,
- * nsGFSYNR0: 0x450)
- */
-#define ARM_SMMU_GR0_NS(smmu)                                          \
-       ((smmu)->base +                                                 \
-               ((smmu->options & ARM_SMMU_OPT_SECURE_CFG_ACCESS)       \
-                       ? 0x400 : 0))
-
-/*
- * Some 64-bit registers only make sense to write atomically, but in such
- * cases all the data relevant to AArch32 formats lies within the lower word,
- * therefore this actually makes more sense than it might first appear.
- */
-#ifdef CONFIG_64BIT
-#define smmu_write_atomic_lq           writeq_relaxed
-#else
-#define smmu_write_atomic_lq           writel_relaxed
-#endif
-
-/* Translation context bank */
-#define ARM_SMMU_CB(smmu, n)   ((smmu)->cb_base + ((n) << (smmu)->pgshift))
-
 #define MSI_IOVA_BASE                  0x8000000
 #define MSI_IOVA_LENGTH                        0x100000
 
@@ -113,19 +72,6 @@ module_param(disable_bypass, bool, S_IRUGO);
 MODULE_PARM_DESC(disable_bypass,
        "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
 
-enum arm_smmu_arch_version {
-       ARM_SMMU_V1,
-       ARM_SMMU_V1_64K,
-       ARM_SMMU_V2,
-};
-
-enum arm_smmu_implementation {
-       GENERIC_SMMU,
-       ARM_MMU500,
-       CAVIUM_SMMUV2,
-       QCOM_SMMUV2,
-};
-
 struct arm_smmu_s2cr {
        struct iommu_group              *group;
        int                             count;
@@ -163,117 +109,8 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
        for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
-struct arm_smmu_device {
-       struct device                   *dev;
-
-       void __iomem                    *base;
-       void __iomem                    *cb_base;
-       unsigned long                   pgshift;
-
-#define ARM_SMMU_FEAT_COHERENT_WALK    (1 << 0)
-#define ARM_SMMU_FEAT_STREAM_MATCH     (1 << 1)
-#define ARM_SMMU_FEAT_TRANS_S1         (1 << 2)
-#define ARM_SMMU_FEAT_TRANS_S2         (1 << 3)
-#define ARM_SMMU_FEAT_TRANS_NESTED     (1 << 4)
-#define ARM_SMMU_FEAT_TRANS_OPS                (1 << 5)
-#define ARM_SMMU_FEAT_VMID16           (1 << 6)
-#define ARM_SMMU_FEAT_FMT_AARCH64_4K   (1 << 7)
-#define ARM_SMMU_FEAT_FMT_AARCH64_16K  (1 << 8)
-#define ARM_SMMU_FEAT_FMT_AARCH64_64K  (1 << 9)
-#define ARM_SMMU_FEAT_FMT_AARCH32_L    (1 << 10)
-#define ARM_SMMU_FEAT_FMT_AARCH32_S    (1 << 11)
-#define ARM_SMMU_FEAT_EXIDS            (1 << 12)
-       u32                             features;
-
-#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
-       u32                             options;
-       enum arm_smmu_arch_version      version;
-       enum arm_smmu_implementation    model;
-
-       u32                             num_context_banks;
-       u32                             num_s2_context_banks;
-       DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
-       struct arm_smmu_cb              *cbs;
-       atomic_t                        irptndx;
-
-       u32                             num_mapping_groups;
-       u16                             streamid_mask;
-       u16                             smr_mask_mask;
-       struct arm_smmu_smr             *smrs;
-       struct arm_smmu_s2cr            *s2crs;
-       struct mutex                    stream_map_mutex;
-
-       unsigned long                   va_size;
-       unsigned long                   ipa_size;
-       unsigned long                   pa_size;
-       unsigned long                   pgsize_bitmap;
-
-       u32                             num_global_irqs;
-       u32                             num_context_irqs;
-       unsigned int                    *irqs;
-       struct clk_bulk_data            *clks;
-       int                             num_clks;
-
-       u32                             cavium_id_base; /* Specific to Cavium */
-
-       spinlock_t                      global_sync_lock;
-
-       /* IOMMU core code handle */
-       struct iommu_device             iommu;
-};
-
-enum arm_smmu_context_fmt {
-       ARM_SMMU_CTX_FMT_NONE,
-       ARM_SMMU_CTX_FMT_AARCH64,
-       ARM_SMMU_CTX_FMT_AARCH32_L,
-       ARM_SMMU_CTX_FMT_AARCH32_S,
-};
-
-struct arm_smmu_cfg {
-       u8                              cbndx;
-       u8                              irptndx;
-       union {
-               u16                     asid;
-               u16                     vmid;
-       };
-       u32                             cbar;
-       enum arm_smmu_context_fmt       fmt;
-};
-#define INVALID_IRPTNDX                        0xff
-
-enum arm_smmu_domain_stage {
-       ARM_SMMU_DOMAIN_S1 = 0,
-       ARM_SMMU_DOMAIN_S2,
-       ARM_SMMU_DOMAIN_NESTED,
-       ARM_SMMU_DOMAIN_BYPASS,
-};
-
-struct arm_smmu_domain {
-       struct arm_smmu_device          *smmu;
-       struct io_pgtable_ops           *pgtbl_ops;
-       const struct iommu_gather_ops   *tlb_ops;
-       struct arm_smmu_cfg             cfg;
-       enum arm_smmu_domain_stage      stage;
-       bool                            non_strict;
-       struct mutex                    init_mutex; /* Protects smmu pointer */
-       spinlock_t                      cb_lock; /* Serialises ATS1* ops and TLB syncs */
-       struct iommu_domain             domain;
-};
-
-struct arm_smmu_option_prop {
-       u32 opt;
-       const char *prop;
-};
-
-static atomic_t cavium_smmu_context_count = ATOMIC_INIT(0);
-
 static bool using_legacy_binding, using_generic_binding;
 
-static struct arm_smmu_option_prop arm_smmu_options[] = {
-       { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
-       { 0, NULL},
-};
-
 static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
 {
        if (pm_runtime_enabled(smmu->dev))
@@ -293,20 +130,6 @@ 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);
-}
-
 static struct device_node *dev_get_dev_node(struct device *dev)
 {
        if (dev_is_pci(dev)) {
@@ -415,15 +238,17 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
 }
 
 /* Wait for any pending TLB invalidations to complete */
-static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu,
-                               void __iomem *sync, void __iomem *status)
+static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
+                               int sync, int status)
 {
        unsigned int spin_cnt, delay;
+       u32 reg;
 
-       writel_relaxed(QCOM_DUMMY_VAL, sync);
+       arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL);
        for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) {
                for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) {
-                       if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE))
+                       reg = arm_smmu_readl(smmu, page, status);
+                       if (!(reg & sTLBGSTATUS_GSACTIVE))
                                return;
                        cpu_relax();
                }
@@ -435,12 +260,11 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu,
 
 static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu)
 {
-       void __iomem *base = ARM_SMMU_GR0(smmu);
        unsigned long flags;
 
        spin_lock_irqsave(&smmu->global_sync_lock, flags);
-       __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC,
-                           base + ARM_SMMU_GR0_sTLBGSTATUS);
+       __arm_smmu_tlb_sync(smmu, ARM_SMMU_GR0, ARM_SMMU_GR0_sTLBGSYNC,
+                           ARM_SMMU_GR0_sTLBGSTATUS);
        spin_unlock_irqrestore(&smmu->global_sync_lock, flags);
 }
 
@@ -448,12 +272,11 @@ static void arm_smmu_tlb_sync_context(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
-       void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
        unsigned long flags;
 
        spin_lock_irqsave(&smmu_domain->cb_lock, flags);
-       __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC,
-                           base + ARM_SMMU_CB_TLBSTATUS);
+       __arm_smmu_tlb_sync(smmu, ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx),
+                           ARM_SMMU_CB_TLBSYNC, ARM_SMMU_CB_TLBSTATUS);
        spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
 }
 
@@ -467,14 +290,13 @@ static void arm_smmu_tlb_sync_vmid(void *cookie)
 static void arm_smmu_tlb_inv_context_s1(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
-       struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
-       void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
-
        /*
-        * NOTE: this is not a relaxed write; it needs to guarantee that PTEs
-        * cleared by the current CPU are visible to the SMMU before the TLBI.
+        * The TLBI write may be relaxed, so ensure that PTEs cleared by the
+        * current CPU are visible beforehand.
         */
-       writel(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
+       wmb();
+       arm_smmu_cb_write(smmu_domain->smmu, smmu_domain->cfg.cbndx,
+                         ARM_SMMU_CB_S1_TLBIASID, smmu_domain->cfg.asid);
        arm_smmu_tlb_sync_context(cookie);
 }
 
@@ -482,87 +304,143 @@ static void arm_smmu_tlb_inv_context_s2(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
-       void __iomem *base = ARM_SMMU_GR0(smmu);
 
-       /* NOTE: see above */
-       writel(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID);
+       /* See above */
+       wmb();
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid);
        arm_smmu_tlb_sync_global(smmu);
 }
 
-static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
-                                         size_t granule, bool leaf, void *cookie)
+static void arm_smmu_tlb_inv_range_s1(unsigned long iova, size_t size,
+                                     size_t granule, bool leaf, void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
+       struct arm_smmu_device *smmu = smmu_domain->smmu;
        struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
-       bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
-       void __iomem *reg = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
+       int reg, idx = cfg->cbndx;
 
-       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
                wmb();
 
-       if (stage1) {
-               reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
-
-               if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) {
-                       iova &= ~12UL;
-                       iova |= cfg->asid;
-                       do {
-                               writel_relaxed(iova, reg);
-                               iova += granule;
-                       } while (size -= granule);
-               } else {
-                       iova >>= 12;
-                       iova |= (u64)cfg->asid << 48;
-                       do {
-                               writeq_relaxed(iova, reg);
-                               iova += granule >> 12;
-                       } while (size -= granule);
-               }
+       reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
+
+       if (cfg->fmt != ARM_SMMU_CTX_FMT_AARCH64) {
+               iova = (iova >> 12) << 12;
+               iova |= cfg->asid;
+               do {
+                       arm_smmu_cb_write(smmu, idx, reg, iova);
+                       iova += granule;
+               } while (size -= granule);
        } else {
-               reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
-                             ARM_SMMU_CB_S2_TLBIIPAS2;
                iova >>= 12;
+               iova |= (u64)cfg->asid << 48;
                do {
-                       smmu_write_atomic_lq(iova, reg);
+                       arm_smmu_cb_writeq(smmu, idx, reg, iova);
                        iova += granule >> 12;
                } while (size -= granule);
        }
 }
 
+static void arm_smmu_tlb_inv_range_s2(unsigned long iova, size_t size,
+                                     size_t granule, bool leaf, void *cookie)
+{
+       struct arm_smmu_domain *smmu_domain = cookie;
+       struct arm_smmu_device *smmu = smmu_domain->smmu;
+       int reg, idx = smmu_domain->cfg.cbndx;
+
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+               wmb();
+
+       reg = leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : ARM_SMMU_CB_S2_TLBIIPAS2;
+       iova >>= 12;
+       do {
+               if (smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64)
+                       arm_smmu_cb_writeq(smmu, idx, reg, iova);
+               else
+                       arm_smmu_cb_write(smmu, idx, reg, iova);
+               iova += granule >> 12;
+       } while (size -= granule);
+}
+
 /*
  * On MMU-401 at least, the cost of firing off multiple TLBIVMIDs appears
  * almost negligible, but the benefit of getting the first one in as far ahead
  * of the sync as possible is significant, hence we don't just make this a
- * no-op and set .tlb_sync to arm_smmu_inv_context_s2() as you might think.
+ * no-op and set .tlb_sync to arm_smmu_tlb_inv_context_s2() as you might think.
  */
 static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size,
                                         size_t granule, bool leaf, void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
-       void __iomem *base = ARM_SMMU_GR0(smmu_domain->smmu);
+       struct arm_smmu_device *smmu = smmu_domain->smmu;
 
-       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
                wmb();
 
-       writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIVMID, smmu_domain->cfg.vmid);
+}
+
+static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
+                                 size_t granule, void *cookie)
+{
+       struct arm_smmu_domain *smmu_domain = cookie;
+       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+
+       ops->tlb_inv_range(iova, size, granule, false, cookie);
+       ops->tlb_sync(cookie);
+}
+
+static void arm_smmu_tlb_inv_leaf(unsigned long iova, size_t size,
+                                 size_t granule, void *cookie)
+{
+       struct arm_smmu_domain *smmu_domain = cookie;
+       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+
+       ops->tlb_inv_range(iova, size, granule, true, cookie);
+       ops->tlb_sync(cookie);
+}
+
+static void arm_smmu_tlb_add_page(struct iommu_iotlb_gather *gather,
+                                 unsigned long iova, size_t granule,
+                                 void *cookie)
+{
+       struct arm_smmu_domain *smmu_domain = cookie;
+       const struct arm_smmu_flush_ops *ops = smmu_domain->flush_ops;
+
+       ops->tlb_inv_range(iova, granule, granule, true, cookie);
 }
 
-static const struct iommu_gather_ops arm_smmu_s1_tlb_ops = {
-       .tlb_flush_all  = arm_smmu_tlb_inv_context_s1,
-       .tlb_add_flush  = arm_smmu_tlb_inv_range_nosync,
-       .tlb_sync       = arm_smmu_tlb_sync_context,
+static const struct arm_smmu_flush_ops arm_smmu_s1_tlb_ops = {
+       .tlb = {
+               .tlb_flush_all  = arm_smmu_tlb_inv_context_s1,
+               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
+               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
+               .tlb_add_page   = arm_smmu_tlb_add_page,
+       },
+       .tlb_inv_range          = arm_smmu_tlb_inv_range_s1,
+       .tlb_sync               = arm_smmu_tlb_sync_context,
 };
 
-static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v2 = {
-       .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
-       .tlb_add_flush  = arm_smmu_tlb_inv_range_nosync,
-       .tlb_sync       = arm_smmu_tlb_sync_context,
+static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v2 = {
+       .tlb = {
+               .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
+               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
+               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
+               .tlb_add_page   = arm_smmu_tlb_add_page,
+       },
+       .tlb_inv_range          = arm_smmu_tlb_inv_range_s2,
+       .tlb_sync               = arm_smmu_tlb_sync_context,
 };
 
-static const struct iommu_gather_ops arm_smmu_s2_tlb_ops_v1 = {
-       .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
-       .tlb_add_flush  = arm_smmu_tlb_inv_vmid_nosync,
-       .tlb_sync       = arm_smmu_tlb_sync_vmid,
+static const struct arm_smmu_flush_ops arm_smmu_s2_tlb_ops_v1 = {
+       .tlb = {
+               .tlb_flush_all  = arm_smmu_tlb_inv_context_s2,
+               .tlb_flush_walk = arm_smmu_tlb_inv_walk,
+               .tlb_flush_leaf = arm_smmu_tlb_inv_leaf,
+               .tlb_add_page   = arm_smmu_tlb_add_page,
+       },
+       .tlb_inv_range          = arm_smmu_tlb_inv_vmid_nosync,
+       .tlb_sync               = arm_smmu_tlb_sync_vmid,
 };
 
 static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
@@ -571,26 +449,22 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
        unsigned long iova;
        struct iommu_domain *domain = dev;
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-       struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
        struct arm_smmu_device *smmu = smmu_domain->smmu;
-       void __iomem *gr1_base = ARM_SMMU_GR1(smmu);
-       void __iomem *cb_base;
-
-       cb_base = ARM_SMMU_CB(smmu, cfg->cbndx);
-       fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+       int idx = smmu_domain->cfg.cbndx;
 
+       fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR);
        if (!(fsr & FSR_FAULT))
                return IRQ_NONE;
 
-       fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
-       iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
-       cbfrsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx));
+       fsynr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSYNR0);
+       iova = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_FAR);
+       cbfrsynra = arm_smmu_gr1_read(smmu, ARM_SMMU_GR1_CBFRSYNRA(idx));
 
        dev_err_ratelimited(smmu->dev,
        "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cbfrsynra=0x%x, cb=%d\n",
-                           fsr, iova, fsynr, cbfrsynra, cfg->cbndx);
+                           fsr, iova, fsynr, cbfrsynra, idx);
 
-       writel(fsr, cb_base + ARM_SMMU_CB_FSR);
+       arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr);
        return IRQ_HANDLED;
 }
 
@@ -598,12 +472,11 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
 {
        u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
        struct arm_smmu_device *smmu = dev;
-       void __iomem *gr0_base = ARM_SMMU_GR0_NS(smmu);
 
-       gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
-       gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
-       gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
-       gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
+       gfsr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR);
+       gfsynr0 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR0);
+       gfsynr1 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR1);
+       gfsynr2 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR2);
 
        if (!gfsr)
                return IRQ_NONE;
@@ -614,7 +487,7 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
                "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
                gfsr, gfsynr0, gfsynr1, gfsynr2);
 
-       writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, gfsr);
        return IRQ_HANDLED;
 }
 
@@ -627,16 +500,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
 
        cb->cfg = cfg;
 
-       /* TTBCR */
+       /* TCR */
        if (stage1) {
                if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
                        cb->tcr[0] = pgtbl_cfg->arm_v7s_cfg.tcr;
                } else {
                        cb->tcr[0] = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
                        cb->tcr[1] = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
-                       cb->tcr[1] |= TTBCR2_SEP_UPSTREAM;
+                       cb->tcr[1] |= FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM);
                        if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
-                               cb->tcr[1] |= TTBCR2_AS;
+                               cb->tcr[1] |= TCR2_AS;
                }
        } else {
                cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
@@ -649,9 +522,9 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
                        cb->ttbr[1] = pgtbl_cfg->arm_v7s_cfg.ttbr[1];
                } else {
                        cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
-                       cb->ttbr[0] |= (u64)cfg->asid << TTBRn_ASID_SHIFT;
+                       cb->ttbr[0] |= FIELD_PREP(TTBRn_ASID, cfg->asid);
                        cb->ttbr[1] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
-                       cb->ttbr[1] |= (u64)cfg->asid << TTBRn_ASID_SHIFT;
+                       cb->ttbr[1] |= FIELD_PREP(TTBRn_ASID, cfg->asid);
                }
        } else {
                cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
@@ -675,74 +548,71 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
        bool stage1;
        struct arm_smmu_cb *cb = &smmu->cbs[idx];
        struct arm_smmu_cfg *cfg = cb->cfg;
-       void __iomem *cb_base, *gr1_base;
-
-       cb_base = ARM_SMMU_CB(smmu, idx);
 
        /* Unassigned context banks only need disabling */
        if (!cfg) {
-               writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, 0);
                return;
        }
 
-       gr1_base = ARM_SMMU_GR1(smmu);
        stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
 
        /* CBA2R */
        if (smmu->version > ARM_SMMU_V1) {
                if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
-                       reg = CBA2R_RW64_64BIT;
+                       reg = CBA2R_VA64;
                else
-                       reg = CBA2R_RW64_32BIT;
+                       reg = 0;
                /* 16-bit VMIDs live in CBA2R */
                if (smmu->features & ARM_SMMU_FEAT_VMID16)
-                       reg |= cfg->vmid << CBA2R_VMID_SHIFT;
+                       reg |= FIELD_PREP(CBA2R_VMID16, cfg->vmid);
 
-               writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(idx));
+               arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBA2R(idx), reg);
        }
 
        /* CBAR */
-       reg = cfg->cbar;
+       reg = FIELD_PREP(CBAR_TYPE, cfg->cbar);
        if (smmu->version < ARM_SMMU_V2)
-               reg |= cfg->irptndx << CBAR_IRPTNDX_SHIFT;
+               reg |= FIELD_PREP(CBAR_IRPTNDX, cfg->irptndx);
 
        /*
         * Use the weakest shareability/memory types, so they are
         * overridden by the ttbcr/pte.
         */
        if (stage1) {
-               reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
-                       (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+               reg |= FIELD_PREP(CBAR_S1_BPSHCFG, CBAR_S1_BPSHCFG_NSH) |
+                       FIELD_PREP(CBAR_S1_MEMATTR, CBAR_S1_MEMATTR_WB);
        } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) {
                /* 8-bit VMIDs live in CBAR */
-               reg |= cfg->vmid << CBAR_VMID_SHIFT;
+               reg |= FIELD_PREP(CBAR_VMID, cfg->vmid);
        }
-       writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(idx));
+       arm_smmu_gr1_write(smmu, ARM_SMMU_GR1_CBAR(idx), reg);
 
        /*
-        * TTBCR
+        * TCR
         * We must write this before the TTBRs, since it determines the
         * access behaviour of some fields (in particular, ASID[15:8]).
         */
        if (stage1 && smmu->version > ARM_SMMU_V1)
-               writel_relaxed(cb->tcr[1], cb_base + ARM_SMMU_CB_TTBCR2);
-       writel_relaxed(cb->tcr[0], cb_base + ARM_SMMU_CB_TTBCR);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TCR2, cb->tcr[1]);
+       arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TCR, cb->tcr[0]);
 
        /* TTBRs */
        if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
-               writel_relaxed(cfg->asid, cb_base + ARM_SMMU_CB_CONTEXTIDR);
-               writel_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0);
-               writel_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_CONTEXTIDR, cfg->asid);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TTBR0, cb->ttbr[0]);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_TTBR1, cb->ttbr[1]);
        } else {
-               writeq_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0);
+               arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_TTBR0, cb->ttbr[0]);
                if (stage1)
-                       writeq_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1);
+                       arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_TTBR1,
+                                          cb->ttbr[1]);
        }
 
        /* MAIRs (stage-1 only) */
        if (stage1) {
-               writel_relaxed(cb->mair[0], cb_base + ARM_SMMU_CB_S1_MAIR0);
-               writel_relaxed(cb->mair[1], cb_base + ARM_SMMU_CB_S1_MAIR1);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_S1_MAIR0, cb->mair[0]);
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_S1_MAIR1, cb->mair[1]);
        }
 
        /* SCTLR */
@@ -752,7 +622,7 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
        if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
                reg |= SCTLR_E;
 
-       writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR);
+       arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg);
 }
 
 static int arm_smmu_init_domain_context(struct iommu_domain *domain,
@@ -842,7 +712,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                        ias = min(ias, 32UL);
                        oas = min(oas, 32UL);
                }
-               smmu_domain->tlb_ops = &arm_smmu_s1_tlb_ops;
+               smmu_domain->flush_ops = &arm_smmu_s1_tlb_ops;
                break;
        case ARM_SMMU_DOMAIN_NESTED:
                /*
@@ -862,9 +732,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                        oas = min(oas, 40UL);
                }
                if (smmu->version == ARM_SMMU_V2)
-                       smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v2;
+                       smmu_domain->flush_ops = &arm_smmu_s2_tlb_ops_v2;
                else
-                       smmu_domain->tlb_ops = &arm_smmu_s2_tlb_ops_v1;
+                       smmu_domain->flush_ops = &arm_smmu_s2_tlb_ops_v1;
                break;
        default:
                ret = -EINVAL;
@@ -884,23 +754,29 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
        }
 
        if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2)
-               cfg->vmid = cfg->cbndx + 1 + smmu->cavium_id_base;
+               cfg->vmid = cfg->cbndx + 1;
        else
-               cfg->asid = cfg->cbndx + smmu->cavium_id_base;
+               cfg->asid = cfg->cbndx;
+
+       smmu_domain->smmu = smmu;
+       if (smmu->impl && smmu->impl->init_context) {
+               ret = smmu->impl->init_context(smmu_domain);
+               if (ret)
+                       goto out_unlock;
+       }
 
        pgtbl_cfg = (struct io_pgtable_cfg) {
                .pgsize_bitmap  = smmu->pgsize_bitmap,
                .ias            = ias,
                .oas            = oas,
                .coherent_walk  = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK,
-               .tlb            = smmu_domain->tlb_ops,
+               .tlb            = &smmu_domain->flush_ops->tlb,
                .iommu_dev      = smmu->dev,
        };
 
        if (smmu_domain->non_strict)
                pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
 
-       smmu_domain->smmu = smmu;
        pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
        if (!pgtbl_ops) {
                ret = -ENOMEM;
@@ -1019,24 +895,24 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
 static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx)
 {
        struct arm_smmu_smr *smr = smmu->smrs + idx;
-       u32 reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT;
+       u32 reg = FIELD_PREP(SMR_ID, smr->id) | FIELD_PREP(SMR_MASK, smr->mask);
 
        if (!(smmu->features & ARM_SMMU_FEAT_EXIDS) && smr->valid)
                reg |= SMR_VALID;
-       writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), reg);
 }
 
 static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx)
 {
        struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx;
-       u32 reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT |
-                 (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT |
-                 (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT;
+       u32 reg = FIELD_PREP(S2CR_TYPE, s2cr->type) |
+                 FIELD_PREP(S2CR_CBNDX, s2cr->cbndx) |
+                 FIELD_PREP(S2CR_PRIVCFG, s2cr->privcfg);
 
        if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs &&
            smmu->smrs[idx].valid)
                reg |= S2CR_EXIDVALID;
-       writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_S2CR(idx), reg);
 }
 
 static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx)
@@ -1052,7 +928,6 @@ static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx)
  */
 static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu)
 {
-       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
        u32 smr;
 
        if (!smmu->smrs)
@@ -1063,15 +938,15 @@ static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu)
         * bits are set, so check each one separately. We can reject
         * masters later if they try to claim IDs outside these masks.
         */
-       smr = smmu->streamid_mask << SMR_ID_SHIFT;
-       writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
-       smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
-       smmu->streamid_mask = smr >> SMR_ID_SHIFT;
+       smr = FIELD_PREP(SMR_ID, smmu->streamid_mask);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
+       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+       smmu->streamid_mask = FIELD_GET(SMR_ID, smr);
 
-       smr = smmu->streamid_mask << SMR_MASK_SHIFT;
-       writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
-       smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
-       smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT;
+       smr = FIELD_PREP(SMR_MASK, smmu->streamid_mask);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
+       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+       smmu->smr_mask_mask = FIELD_GET(SMR_MASK, smr);
 }
 
 static int arm_smmu_find_sme(struct arm_smmu_device *smmu, u16 id, u16 mask)
@@ -1140,8 +1015,8 @@ static int arm_smmu_master_alloc_smes(struct device *dev)
        mutex_lock(&smmu->stream_map_mutex);
        /* Figure out a viable stream map entry allocation */
        for_each_cfg_sme(fwspec, i, idx) {
-               u16 sid = fwspec->ids[i];
-               u16 mask = fwspec->ids[i] >> SMR_MASK_SHIFT;
+               u16 sid = FIELD_GET(SMR_ID, fwspec->ids[i]);
+               u16 mask = FIELD_GET(SMR_MASK, fwspec->ids[i]);
 
                if (idx != INVALID_SMENDX) {
                        ret = -EEXIST;
@@ -1301,7 +1176,7 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
-                            size_t size)
+                            size_t size, struct iommu_iotlb_gather *gather)
 {
        struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
        struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
@@ -1311,7 +1186,7 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
                return 0;
 
        arm_smmu_rpm_get(smmu);
-       ret = ops->unmap(ops, iova, size);
+       ret = ops->unmap(ops, iova, size, gather);
        arm_smmu_rpm_put(smmu);
 
        return ret;
@@ -1322,21 +1197,22 @@ static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_device *smmu = smmu_domain->smmu;
 
-       if (smmu_domain->tlb_ops) {
+       if (smmu_domain->flush_ops) {
                arm_smmu_rpm_get(smmu);
-               smmu_domain->tlb_ops->tlb_flush_all(smmu_domain);
+               smmu_domain->flush_ops->tlb.tlb_flush_all(smmu_domain);
                arm_smmu_rpm_put(smmu);
        }
 }
 
-static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
+static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
+                               struct iommu_iotlb_gather *gather)
 {
        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct arm_smmu_device *smmu = smmu_domain->smmu;
 
-       if (smmu_domain->tlb_ops) {
+       if (smmu_domain->flush_ops) {
                arm_smmu_rpm_get(smmu);
-               smmu_domain->tlb_ops->tlb_sync(smmu_domain);
+               smmu_domain->flush_ops->tlb_sync(smmu_domain);
                arm_smmu_rpm_put(smmu);
        }
 }
@@ -1349,28 +1225,25 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
        struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
        struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
        struct device *dev = smmu->dev;
-       void __iomem *cb_base;
+       void __iomem *reg;
        u32 tmp;
        u64 phys;
        unsigned long va, flags;
-       int ret;
+       int ret, idx = cfg->cbndx;
 
        ret = arm_smmu_rpm_get(smmu);
        if (ret < 0)
                return 0;
 
-       cb_base = ARM_SMMU_CB(smmu, cfg->cbndx);
-
        spin_lock_irqsave(&smmu_domain->cb_lock, flags);
-       /* ATS1 registers can only be written atomically */
        va = iova & ~0xfffUL;
-       if (smmu->version == ARM_SMMU_V2)
-               smmu_write_atomic_lq(va, cb_base + ARM_SMMU_CB_ATS1PR);
-       else /* Register is only 32-bit in v1 */
-               writel_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR);
+       if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
+               arm_smmu_cb_writeq(smmu, idx, ARM_SMMU_CB_ATS1PR, va);
+       else
+               arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_ATS1PR, va);
 
-       if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
-                                     !(tmp & ATSR_ACTIVE), 5, 50)) {
+       reg = arm_smmu_page(smmu, ARM_SMMU_CB(smmu, idx)) + ARM_SMMU_CB_ATSR;
+       if (readl_poll_timeout_atomic(reg, tmp, !(tmp & ATSR_ACTIVE), 5, 50)) {
                spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
                dev_err(dev,
                        "iova to phys timed out on %pad. Falling back to software table walk.\n",
@@ -1378,7 +1251,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
                return ops->iova_to_phys(ops, iova);
        }
 
-       phys = readq_relaxed(cb_base + ARM_SMMU_CB_PAR);
+       phys = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_PAR);
        spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
        if (phys & CB_PAR_F) {
                dev_err(dev, "translation fault!\n");
@@ -1466,8 +1339,8 @@ static int arm_smmu_add_device(struct device *dev)
 
        ret = -EINVAL;
        for (i = 0; i < fwspec->num_ids; i++) {
-               u16 sid = fwspec->ids[i];
-               u16 mask = fwspec->ids[i] >> SMR_MASK_SHIFT;
+               u16 sid = FIELD_GET(SMR_ID, fwspec->ids[i]);
+               u16 mask = FIELD_GET(SMR_MASK, fwspec->ids[i]);
 
                if (sid & ~smmu->streamid_mask) {
                        dev_err(dev, "stream ID 0x%x out of range for SMMU (0x%x)\n",
@@ -1648,12 +1521,12 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
        u32 mask, fwid = 0;
 
        if (args->args_count > 0)
-               fwid |= (u16)args->args[0];
+               fwid |= FIELD_PREP(SMR_ID, args->args[0]);
 
        if (args->args_count > 1)
-               fwid |= (u16)args->args[1] << SMR_MASK_SHIFT;
+               fwid |= FIELD_PREP(SMR_MASK, args->args[1]);
        else if (!of_property_read_u32(args->np, "stream-match-mask", &mask))
-               fwid |= (u16)mask << SMR_MASK_SHIFT;
+               fwid |= FIELD_PREP(SMR_MASK, mask);
 
        return iommu_fwspec_add_ids(dev, &fwid, 1);
 }
@@ -1706,13 +1579,12 @@ static struct iommu_ops arm_smmu_ops = {
 
 static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
 {
-       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
        int i;
-       u32 reg, major;
+       u32 reg;
 
        /* clear global FSR */
-       reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR);
-       writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR);
+       reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, reg);
 
        /*
         * Reset stream mapping groups: Initial values mark all SMRn as
@@ -1721,47 +1593,17 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
        for (i = 0; i < smmu->num_mapping_groups; ++i)
                arm_smmu_write_sme(smmu, i);
 
-       if (smmu->model == ARM_MMU500) {
-               /*
-                * Before clearing ARM_MMU500_ACTLR_CPRE, need to
-                * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK
-                * bit is only present in MMU-500r2 onwards.
-                */
-               reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7);
-               major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK;
-               reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR);
-               if (major >= 2)
-                       reg &= ~ARM_MMU500_ACR_CACHE_LOCK;
-               /*
-                * Allow unmatched Stream IDs to allocate bypass
-                * TLB entries for reduced latency.
-                */
-               reg |= ARM_MMU500_ACR_SMTNMB_TLBEN | ARM_MMU500_ACR_S2CRB_TLBEN;
-               writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR);
-       }
-
        /* Make sure all context banks are disabled and clear CB_FSR  */
        for (i = 0; i < smmu->num_context_banks; ++i) {
-               void __iomem *cb_base = ARM_SMMU_CB(smmu, i);
-
                arm_smmu_write_context_bank(smmu, i);
-               writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR);
-               /*
-                * Disable MMU-500's not-particularly-beneficial next-page
-                * prefetcher for the sake of errata #841119 and #826419.
-                */
-               if (smmu->model == ARM_MMU500) {
-                       reg = readl_relaxed(cb_base + ARM_SMMU_CB_ACTLR);
-                       reg &= ~ARM_MMU500_ACTLR_CPRE;
-                       writel_relaxed(reg, cb_base + ARM_SMMU_CB_ACTLR);
-               }
+               arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_FSR, FSR_FAULT);
        }
 
        /* Invalidate the TLB, just in case */
-       writel_relaxed(QCOM_DUMMY_VAL, gr0_base + ARM_SMMU_GR0_TLBIALLH);
-       writel_relaxed(QCOM_DUMMY_VAL, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIALLH, QCOM_DUMMY_VAL);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_TLBIALLNSNH, QCOM_DUMMY_VAL);
 
-       reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+       reg = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sCR0);
 
        /* Enable fault reporting */
        reg |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE);
@@ -1780,7 +1622,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
        reg &= ~sCR0_FB;
 
        /* Don't upgrade barriers */
-       reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
+       reg &= ~(sCR0_BSU);
 
        if (smmu->features & ARM_SMMU_FEAT_VMID16)
                reg |= sCR0_VMID16EN;
@@ -1788,9 +1630,12 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
        if (smmu->features & ARM_SMMU_FEAT_EXIDS)
                reg |= sCR0_EXIDENABLE;
 
+       if (smmu->impl && smmu->impl->reset)
+               smmu->impl->reset(smmu);
+
        /* Push the button */
        arm_smmu_tlb_sync_global(smmu);
-       writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, reg);
 }
 
 static int arm_smmu_id_size_to_bits(int size)
@@ -1814,8 +1659,7 @@ static int arm_smmu_id_size_to_bits(int size)
 
 static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
 {
-       unsigned long size;
-       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+       unsigned int size;
        u32 id;
        bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
        int i;
@@ -1825,7 +1669,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                        smmu->version == ARM_SMMU_V2 ? 2 : 1);
 
        /* ID0 */
-       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
+       id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID0);
 
        /* Restrict available stages based on module parameter */
        if (force_stage == 1)
@@ -1879,12 +1723,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                smmu->features |= ARM_SMMU_FEAT_EXIDS;
                size = 1 << 16;
        } else {
-               size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK);
+               size = 1 << FIELD_GET(ID0_NUMSIDB, id);
        }
        smmu->streamid_mask = size - 1;
        if (id & ID0_SMS) {
                smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
-               size = (id >> ID0_NUMSMRG_SHIFT) & ID0_NUMSMRG_MASK;
+               size = FIELD_GET(ID0_NUMSMRG, id);
                if (size == 0) {
                        dev_err(smmu->dev,
                                "stream-matching supported, but no SMRs present!\n");
@@ -1898,7 +1742,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                        return -ENOMEM;
 
                dev_notice(smmu->dev,
-                          "\tstream matching with %lu register groups", size);
+                          "\tstream matching with %u register groups", size);
        }
        /* s2cr->type == 0 means translation, so initialise explicitly */
        smmu->s2crs = devm_kmalloc_array(smmu->dev, size, sizeof(*smmu->s2crs),
@@ -1919,49 +1763,38 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
        }
 
        /* ID1 */
-       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1);
+       id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID1);
        smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12;
 
        /* Check for size mismatch of SMMU address space from mapped region */
-       size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
-       size <<= smmu->pgshift;
-       if (smmu->cb_base != gr0_base + size)
+       size = 1 << (FIELD_GET(ID1_NUMPAGENDXB, id) + 1);
+       if (smmu->numpage != 2 * size << smmu->pgshift)
                dev_warn(smmu->dev,
-                       "SMMU address space size (0x%lx) differs from mapped region size (0x%tx)!\n",
-                       size * 2, (smmu->cb_base - gr0_base) * 2);
+                       "SMMU address space size (0x%x) differs from mapped region size (0x%x)!\n",
+                       2 * size << smmu->pgshift, smmu->numpage);
+       /* Now properly encode NUMPAGE to subsequently derive SMMU_CB_BASE */
+       smmu->numpage = size;
 
-       smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK;
-       smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK;
+       smmu->num_s2_context_banks = FIELD_GET(ID1_NUMS2CB, id);
+       smmu->num_context_banks = FIELD_GET(ID1_NUMCB, id);
        if (smmu->num_s2_context_banks > smmu->num_context_banks) {
                dev_err(smmu->dev, "impossible number of S2 context banks!\n");
                return -ENODEV;
        }
        dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
                   smmu->num_context_banks, smmu->num_s2_context_banks);
-       /*
-        * Cavium CN88xx erratum #27704.
-        * Ensure ASID and VMID allocation is unique across all SMMUs in
-        * the system.
-        */
-       if (smmu->model == CAVIUM_SMMUV2) {
-               smmu->cavium_id_base =
-                       atomic_add_return(smmu->num_context_banks,
-                                         &cavium_smmu_context_count);
-               smmu->cavium_id_base -= smmu->num_context_banks;
-               dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n");
-       }
        smmu->cbs = devm_kcalloc(smmu->dev, smmu->num_context_banks,
                                 sizeof(*smmu->cbs), GFP_KERNEL);
        if (!smmu->cbs)
                return -ENOMEM;
 
        /* ID2 */
-       id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
-       size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
+       id = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_ID2);
+       size = arm_smmu_id_size_to_bits(FIELD_GET(ID2_IAS, id));
        smmu->ipa_size = size;
 
        /* The output mask is also applied for bypass */
-       size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
+       size = arm_smmu_id_size_to_bits(FIELD_GET(ID2_OAS, id));
        smmu->pa_size = size;
 
        if (id & ID2_VMID16)
@@ -1981,7 +1814,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                if (smmu->version == ARM_SMMU_V1_64K)
                        smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_64K;
        } else {
-               size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
+               size = FIELD_GET(ID2_UBS, id);
                smmu->va_size = arm_smmu_id_size_to_bits(size);
                if (id & ID2_PTFS_4K)
                        smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_4K;
@@ -2018,6 +1851,9 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n",
                           smmu->ipa_size, smmu->pa_size);
 
+       if (smmu->impl && smmu->impl->cfg_probe)
+               return smmu->impl->cfg_probe(smmu);
+
        return 0;
 }
 
@@ -2130,8 +1966,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
        smmu->version = data->version;
        smmu->model = data->model;
 
-       parse_driver_options(smmu);
-
        legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL);
        if (legacy_binding && !using_generic_binding) {
                if (!using_legacy_binding)
@@ -2194,12 +2028,20 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       smmu = arm_smmu_impl_init(smmu);
+       if (IS_ERR(smmu))
+               return PTR_ERR(smmu);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ioaddr = res->start;
        smmu->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(smmu->base))
                return PTR_ERR(smmu->base);
-       smmu->cb_base = smmu->base + resource_size(res) / 2;
+       /*
+        * The resource size should effectively match the value of SMMU_TOP;
+        * stash that temporarily until we know PAGESIZE to validate it with.
+        */
+       smmu->numpage = resource_size(res);
 
        num_irqs = 0;
        while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
@@ -2339,7 +2181,7 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
 
        arm_smmu_rpm_get(smmu);
        /* Turn the thing off */
-       writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, sCR0_CLIENTPD);
        arm_smmu_rpm_put(smmu);
 
        if (pm_runtime_enabled(smmu->dev))
diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h
new file mode 100644 (file)
index 0000000..b19b6ca
--- /dev/null
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * IOMMU API for ARM architected SMMU implementations.
+ *
+ * Copyright (C) 2013 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#ifndef _ARM_SMMU_H
+#define _ARM_SMMU_H
+
+#include <linux/atomic.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/io-pgtable.h>
+#include <linux/iommu.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0              0x0
+#define sCR0_VMID16EN                  BIT(31)
+#define sCR0_BSU                       GENMASK(15, 14)
+#define sCR0_FB                                BIT(13)
+#define sCR0_PTM                       BIT(12)
+#define sCR0_VMIDPNE                   BIT(11)
+#define sCR0_USFCFG                    BIT(10)
+#define sCR0_GCFGFIE                   BIT(5)
+#define sCR0_GCFGFRE                   BIT(4)
+#define sCR0_EXIDENABLE                        BIT(3)
+#define sCR0_GFIE                      BIT(2)
+#define sCR0_GFRE                      BIT(1)
+#define sCR0_CLIENTPD                  BIT(0)
+
+/* Auxiliary Configuration register */
+#define ARM_SMMU_GR0_sACR              0x10
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0               0x20
+#define ID0_S1TS                       BIT(30)
+#define ID0_S2TS                       BIT(29)
+#define ID0_NTS                                BIT(28)
+#define ID0_SMS                                BIT(27)
+#define ID0_ATOSNS                     BIT(26)
+#define ID0_PTFS_NO_AARCH32            BIT(25)
+#define ID0_PTFS_NO_AARCH32S           BIT(24)
+#define ID0_NUMIRPT                    GENMASK(23, 16)
+#define ID0_CTTW                       BIT(14)
+#define ID0_NUMSIDB                    GENMASK(12, 9)
+#define ID0_EXIDS                      BIT(8)
+#define ID0_NUMSMRG                    GENMASK(7, 0)
+
+#define ARM_SMMU_GR0_ID1               0x24
+#define ID1_PAGESIZE                   BIT(31)
+#define ID1_NUMPAGENDXB                        GENMASK(30, 28)
+#define ID1_NUMS2CB                    GENMASK(23, 16)
+#define ID1_NUMCB                      GENMASK(7, 0)
+
+#define ARM_SMMU_GR0_ID2               0x28
+#define ID2_VMID16                     BIT(15)
+#define ID2_PTFS_64K                   BIT(14)
+#define ID2_PTFS_16K                   BIT(13)
+#define ID2_PTFS_4K                    BIT(12)
+#define ID2_UBS                                GENMASK(11, 8)
+#define ID2_OAS                                GENMASK(7, 4)
+#define ID2_IAS                                GENMASK(3, 0)
+
+#define ARM_SMMU_GR0_ID3               0x2c
+#define ARM_SMMU_GR0_ID4               0x30
+#define ARM_SMMU_GR0_ID5               0x34
+#define ARM_SMMU_GR0_ID6               0x38
+
+#define ARM_SMMU_GR0_ID7               0x3c
+#define ID7_MAJOR                      GENMASK(7, 4)
+#define ID7_MINOR                      GENMASK(3, 0)
+
+#define ARM_SMMU_GR0_sGFSR             0x48
+#define ARM_SMMU_GR0_sGFSYNR0          0x50
+#define ARM_SMMU_GR0_sGFSYNR1          0x54
+#define ARM_SMMU_GR0_sGFSYNR2          0x58
+
+/* Global TLB invalidation */
+#define ARM_SMMU_GR0_TLBIVMID          0x64
+#define ARM_SMMU_GR0_TLBIALLNSNH       0x68
+#define ARM_SMMU_GR0_TLBIALLH          0x6c
+#define ARM_SMMU_GR0_sTLBGSYNC         0x70
+
+#define ARM_SMMU_GR0_sTLBGSTATUS       0x74
+#define sTLBGSTATUS_GSACTIVE           BIT(0)
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n)            (0x800 + ((n) << 2))
+#define SMR_VALID                      BIT(31)
+#define SMR_MASK                       GENMASK(31, 16)
+#define SMR_ID                         GENMASK(15, 0)
+
+#define ARM_SMMU_GR0_S2CR(n)           (0xc00 + ((n) << 2))
+#define S2CR_PRIVCFG                   GENMASK(25, 24)
+enum arm_smmu_s2cr_privcfg {
+       S2CR_PRIVCFG_DEFAULT,
+       S2CR_PRIVCFG_DIPAN,
+       S2CR_PRIVCFG_UNPRIV,
+       S2CR_PRIVCFG_PRIV,
+};
+#define S2CR_TYPE                      GENMASK(17, 16)
+enum arm_smmu_s2cr_type {
+       S2CR_TYPE_TRANS,
+       S2CR_TYPE_BYPASS,
+       S2CR_TYPE_FAULT,
+};
+#define S2CR_EXIDVALID                 BIT(10)
+#define S2CR_CBNDX                     GENMASK(7, 0)
+
+/* Context bank attribute registers */
+#define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
+#define CBAR_IRPTNDX                   GENMASK(31, 24)
+#define CBAR_TYPE                      GENMASK(17, 16)
+enum arm_smmu_cbar_type {
+       CBAR_TYPE_S2_TRANS,
+       CBAR_TYPE_S1_TRANS_S2_BYPASS,
+       CBAR_TYPE_S1_TRANS_S2_FAULT,
+       CBAR_TYPE_S1_TRANS_S2_TRANS,
+};
+#define CBAR_S1_MEMATTR                        GENMASK(15, 12)
+#define CBAR_S1_MEMATTR_WB             0xf
+#define CBAR_S1_BPSHCFG                        GENMASK(9, 8)
+#define CBAR_S1_BPSHCFG_NSH            3
+#define CBAR_VMID                      GENMASK(7, 0)
+
+#define ARM_SMMU_GR1_CBFRSYNRA(n)      (0x400 + ((n) << 2))
+
+#define ARM_SMMU_GR1_CBA2R(n)          (0x800 + ((n) << 2))
+#define CBA2R_VMID16                   GENMASK(31, 16)
+#define CBA2R_VA64                     BIT(0)
+
+#define ARM_SMMU_CB_SCTLR              0x0
+#define SCTLR_S1_ASIDPNE               BIT(12)
+#define SCTLR_CFCFG                    BIT(7)
+#define SCTLR_CFIE                     BIT(6)
+#define SCTLR_CFRE                     BIT(5)
+#define SCTLR_E                                BIT(4)
+#define SCTLR_AFE                      BIT(2)
+#define SCTLR_TRE                      BIT(1)
+#define SCTLR_M                                BIT(0)
+
+#define ARM_SMMU_CB_ACTLR              0x4
+
+#define ARM_SMMU_CB_RESUME             0x8
+#define RESUME_TERMINATE               BIT(0)
+
+#define ARM_SMMU_CB_TCR2               0x10
+#define TCR2_SEP                       GENMASK(17, 15)
+#define TCR2_SEP_UPSTREAM              0x7
+#define TCR2_AS                                BIT(4)
+
+#define ARM_SMMU_CB_TTBR0              0x20
+#define ARM_SMMU_CB_TTBR1              0x28
+#define TTBRn_ASID                     GENMASK_ULL(63, 48)
+
+#define ARM_SMMU_CB_TCR                        0x30
+#define ARM_SMMU_CB_CONTEXTIDR         0x34
+#define ARM_SMMU_CB_S1_MAIR0           0x38
+#define ARM_SMMU_CB_S1_MAIR1           0x3c
+
+#define ARM_SMMU_CB_PAR                        0x50
+#define CB_PAR_F                       BIT(0)
+
+#define ARM_SMMU_CB_FSR                        0x58
+#define FSR_MULTI                      BIT(31)
+#define FSR_SS                         BIT(30)
+#define FSR_UUT                                BIT(8)
+#define FSR_ASF                                BIT(7)
+#define FSR_TLBLKF                     BIT(6)
+#define FSR_TLBMCF                     BIT(5)
+#define FSR_EF                         BIT(4)
+#define FSR_PF                         BIT(3)
+#define FSR_AFF                                BIT(2)
+#define FSR_TF                         BIT(1)
+
+#define FSR_IGN                                (FSR_AFF | FSR_ASF | \
+                                        FSR_TLBMCF | FSR_TLBLKF)
+#define FSR_FAULT                      (FSR_MULTI | FSR_SS | FSR_UUT | \
+                                        FSR_EF | FSR_PF | FSR_TF | FSR_IGN)
+
+#define ARM_SMMU_CB_FAR                        0x60
+
+#define ARM_SMMU_CB_FSYNR0             0x68
+#define FSYNR0_WNR                     BIT(4)
+
+#define ARM_SMMU_CB_S1_TLBIVA          0x600
+#define ARM_SMMU_CB_S1_TLBIASID                0x610
+#define ARM_SMMU_CB_S1_TLBIVAL         0x620
+#define ARM_SMMU_CB_S2_TLBIIPAS2       0x630
+#define ARM_SMMU_CB_S2_TLBIIPAS2L      0x638
+#define ARM_SMMU_CB_TLBSYNC            0x7f0
+#define ARM_SMMU_CB_TLBSTATUS          0x7f4
+#define ARM_SMMU_CB_ATS1PR             0x800
+
+#define ARM_SMMU_CB_ATSR               0x8f0
+#define ATSR_ACTIVE                    BIT(0)
+
+
+/* Maximum number of context banks per SMMU */
+#define ARM_SMMU_MAX_CBS               128
+
+
+/* Shared driver definitions */
+enum arm_smmu_arch_version {
+       ARM_SMMU_V1,
+       ARM_SMMU_V1_64K,
+       ARM_SMMU_V2,
+};
+
+enum arm_smmu_implementation {
+       GENERIC_SMMU,
+       ARM_MMU500,
+       CAVIUM_SMMUV2,
+       QCOM_SMMUV2,
+};
+
+struct arm_smmu_device {
+       struct device                   *dev;
+
+       void __iomem                    *base;
+       unsigned int                    numpage;
+       unsigned int                    pgshift;
+
+#define ARM_SMMU_FEAT_COHERENT_WALK    (1 << 0)
+#define ARM_SMMU_FEAT_STREAM_MATCH     (1 << 1)
+#define ARM_SMMU_FEAT_TRANS_S1         (1 << 2)
+#define ARM_SMMU_FEAT_TRANS_S2         (1 << 3)
+#define ARM_SMMU_FEAT_TRANS_NESTED     (1 << 4)
+#define ARM_SMMU_FEAT_TRANS_OPS                (1 << 5)
+#define ARM_SMMU_FEAT_VMID16           (1 << 6)
+#define ARM_SMMU_FEAT_FMT_AARCH64_4K   (1 << 7)
+#define ARM_SMMU_FEAT_FMT_AARCH64_16K  (1 << 8)
+#define ARM_SMMU_FEAT_FMT_AARCH64_64K  (1 << 9)
+#define ARM_SMMU_FEAT_FMT_AARCH32_L    (1 << 10)
+#define ARM_SMMU_FEAT_FMT_AARCH32_S    (1 << 11)
+#define ARM_SMMU_FEAT_EXIDS            (1 << 12)
+       u32                             features;
+
+       enum arm_smmu_arch_version      version;
+       enum arm_smmu_implementation    model;
+       const struct arm_smmu_impl      *impl;
+
+       u32                             num_context_banks;
+       u32                             num_s2_context_banks;
+       DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+       struct arm_smmu_cb              *cbs;
+       atomic_t                        irptndx;
+
+       u32                             num_mapping_groups;
+       u16                             streamid_mask;
+       u16                             smr_mask_mask;
+       struct arm_smmu_smr             *smrs;
+       struct arm_smmu_s2cr            *s2crs;
+       struct mutex                    stream_map_mutex;
+
+       unsigned long                   va_size;
+       unsigned long                   ipa_size;
+       unsigned long                   pa_size;
+       unsigned long                   pgsize_bitmap;
+
+       u32                             num_global_irqs;
+       u32                             num_context_irqs;
+       unsigned int                    *irqs;
+       struct clk_bulk_data            *clks;
+       int                             num_clks;
+
+       spinlock_t                      global_sync_lock;
+
+       /* IOMMU core code handle */
+       struct iommu_device             iommu;
+};
+
+enum arm_smmu_context_fmt {
+       ARM_SMMU_CTX_FMT_NONE,
+       ARM_SMMU_CTX_FMT_AARCH64,
+       ARM_SMMU_CTX_FMT_AARCH32_L,
+       ARM_SMMU_CTX_FMT_AARCH32_S,
+};
+
+struct arm_smmu_cfg {
+       u8                              cbndx;
+       u8                              irptndx;
+       union {
+               u16                     asid;
+               u16                     vmid;
+       };
+       enum arm_smmu_cbar_type         cbar;
+       enum arm_smmu_context_fmt       fmt;
+};
+#define INVALID_IRPTNDX                        0xff
+
+enum arm_smmu_domain_stage {
+       ARM_SMMU_DOMAIN_S1 = 0,
+       ARM_SMMU_DOMAIN_S2,
+       ARM_SMMU_DOMAIN_NESTED,
+       ARM_SMMU_DOMAIN_BYPASS,
+};
+
+struct arm_smmu_flush_ops {
+       struct iommu_flush_ops          tlb;
+       void (*tlb_inv_range)(unsigned long iova, size_t size, size_t granule,
+                             bool leaf, void *cookie);
+       void (*tlb_sync)(void *cookie);
+};
+
+struct arm_smmu_domain {
+       struct arm_smmu_device          *smmu;
+       struct io_pgtable_ops           *pgtbl_ops;
+       const struct arm_smmu_flush_ops *flush_ops;
+       struct arm_smmu_cfg             cfg;
+       enum arm_smmu_domain_stage      stage;
+       bool                            non_strict;
+       struct mutex                    init_mutex; /* Protects smmu pointer */
+       spinlock_t                      cb_lock; /* Serialises ATS1* ops and TLB syncs */
+       struct iommu_domain             domain;
+};
+
+
+/* Implementation details, yay! */
+struct arm_smmu_impl {
+       u32 (*read_reg)(struct arm_smmu_device *smmu, int page, int offset);
+       void (*write_reg)(struct arm_smmu_device *smmu, int page, int offset,
+                         u32 val);
+       u64 (*read_reg64)(struct arm_smmu_device *smmu, int page, int offset);
+       void (*write_reg64)(struct arm_smmu_device *smmu, int page, int offset,
+                           u64 val);
+       int (*cfg_probe)(struct arm_smmu_device *smmu);
+       int (*reset)(struct arm_smmu_device *smmu);
+       int (*init_context)(struct arm_smmu_domain *smmu_domain);
+};
+
+static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n)
+{
+       return smmu->base + (n << smmu->pgshift);
+}
+
+static inline u32 arm_smmu_readl(struct arm_smmu_device *smmu, int page, int offset)
+{
+       if (smmu->impl && unlikely(smmu->impl->read_reg))
+               return smmu->impl->read_reg(smmu, page, offset);
+       return readl_relaxed(arm_smmu_page(smmu, page) + offset);
+}
+
+static inline void arm_smmu_writel(struct arm_smmu_device *smmu, int page,
+                                  int offset, u32 val)
+{
+       if (smmu->impl && unlikely(smmu->impl->write_reg))
+               smmu->impl->write_reg(smmu, page, offset, val);
+       else
+               writel_relaxed(val, arm_smmu_page(smmu, page) + offset);
+}
+
+static inline u64 arm_smmu_readq(struct arm_smmu_device *smmu, int page, int offset)
+{
+       if (smmu->impl && unlikely(smmu->impl->read_reg64))
+               return smmu->impl->read_reg64(smmu, page, offset);
+       return readq_relaxed(arm_smmu_page(smmu, page) + offset);
+}
+
+static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page,
+                                  int offset, u64 val)
+{
+       if (smmu->impl && unlikely(smmu->impl->write_reg64))
+               smmu->impl->write_reg64(smmu, page, offset, val);
+       else
+               writeq_relaxed(val, arm_smmu_page(smmu, page) + offset);
+}
+
+#define ARM_SMMU_GR0           0
+#define ARM_SMMU_GR1           1
+#define ARM_SMMU_CB(s, n)      ((s)->numpage + (n))
+
+#define arm_smmu_gr0_read(s, o)                \
+       arm_smmu_readl((s), ARM_SMMU_GR0, (o))
+#define arm_smmu_gr0_write(s, o, v)    \
+       arm_smmu_writel((s), ARM_SMMU_GR0, (o), (v))
+
+#define arm_smmu_gr1_read(s, o)                \
+       arm_smmu_readl((s), ARM_SMMU_GR1, (o))
+#define arm_smmu_gr1_write(s, o, v)    \
+       arm_smmu_writel((s), ARM_SMMU_GR1, (o), (v))
+
+#define arm_smmu_cb_read(s, n, o)      \
+       arm_smmu_readl((s), ARM_SMMU_CB((s), (n)), (o))
+#define arm_smmu_cb_write(s, n, o, v)  \
+       arm_smmu_writel((s), ARM_SMMU_CB((s), (n)), (o), (v))
+#define arm_smmu_cb_readq(s, n, o)     \
+       arm_smmu_readq((s), ARM_SMMU_CB((s), (n)), (o))
+#define arm_smmu_cb_writeq(s, n, o, v) \
+       arm_smmu_writeq((s), ARM_SMMU_CB((s), (n)), (o), (v))
+
+struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu);
+
+#endif /* _ARM_SMMU_H */
index a7f9c3e..8f412af 100644 (file)
@@ -303,13 +303,15 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
                u64 size, struct device *dev)
 {
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
-       struct iova_domain *iovad = &cookie->iovad;
        unsigned long order, base_pfn;
+       struct iova_domain *iovad;
        int attr;
 
        if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
                return -EINVAL;
 
+       iovad = &cookie->iovad;
+
        /* Use the smallest supported page size for IOVA granularity */
        order = __ffs(domain->pgsize_bitmap);
        base_pfn = max_t(unsigned long, 1, base >> order);
@@ -444,13 +446,18 @@ static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
        struct iova_domain *iovad = &cookie->iovad;
        size_t iova_off = iova_offset(iovad, dma_addr);
+       struct iommu_iotlb_gather iotlb_gather;
+       size_t unmapped;
 
        dma_addr -= iova_off;
        size = iova_align(iovad, size + iova_off);
+       iommu_iotlb_gather_init(&iotlb_gather);
+
+       unmapped = iommu_unmap_fast(domain, dma_addr, size, &iotlb_gather);
+       WARN_ON(unmapped != size);
 
-       WARN_ON(iommu_unmap_fast(domain, dma_addr, size) != size);
        if (!cookie->fq_domain)
-               iommu_tlb_sync(domain);
+               iommu_tlb_sync(domain, &iotlb_gather);
        iommu_dma_free_iova(cookie, dma_addr, size);
 }
 
@@ -459,13 +466,11 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
 {
        struct iommu_domain *domain = iommu_get_dma_domain(dev);
        struct iommu_dma_cookie *cookie = domain->iova_cookie;
-       size_t iova_off = 0;
+       struct iova_domain *iovad = &cookie->iovad;
+       size_t iova_off = iova_offset(iovad, phys);
        dma_addr_t iova;
 
-       if (cookie->type == IOMMU_DMA_IOVA_COOKIE) {
-               iova_off = iova_offset(&cookie->iovad, phys);
-               size = iova_align(&cookie->iovad, size + iova_off);
-       }
+       size = iova_align(iovad, size + iova_off);
 
        iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
        if (!iova)
@@ -574,7 +579,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
        struct iova_domain *iovad = &cookie->iovad;
        bool coherent = dev_is_dma_coherent(dev);
        int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs);
-       pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+       pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
        unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
        struct page **pages;
        struct sg_table sgt;
@@ -764,7 +769,7 @@ static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents,
                 * - and wouldn't make the resulting output segment too long
                 */
                if (cur_len && !s_iova_off && (dma_addr & seg_mask) &&
-                   (cur_len + s_length <= max_len)) {
+                   (max_len - cur_len >= s_length)) {
                        /* ...then concatenate it with the previous one */
                        cur_len += s_length;
                } else {
@@ -967,15 +972,18 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
 {
        bool coherent = dev_is_dma_coherent(dev);
        size_t alloc_size = PAGE_ALIGN(size);
+       int node = dev_to_node(dev);
        struct page *page = NULL;
        void *cpu_addr;
 
        page = dma_alloc_contiguous(dev, alloc_size, gfp);
+       if (!page)
+               page = alloc_pages_node(node, gfp, get_order(alloc_size));
        if (!page)
                return NULL;
 
        if (IS_ENABLED(CONFIG_DMA_REMAP) && (!coherent || PageHighMem(page))) {
-               pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+               pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
 
                cpu_addr = dma_common_contiguous_remap(page, alloc_size,
                                VM_USERMAP, prot, __builtin_return_address(0));
@@ -1035,7 +1043,7 @@ static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
        unsigned long pfn, off = vma->vm_pgoff;
        int ret;
 
-       vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs);
+       vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
 
        if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
@@ -1147,16 +1155,21 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
        if (!msi_page)
                return NULL;
 
-       iova = __iommu_dma_map(dev, msi_addr, size, prot);
-       if (iova == DMA_MAPPING_ERROR)
+       iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
+       if (!iova)
                goto out_free_page;
 
+       if (iommu_map(domain, iova, msi_addr, size, prot))
+               goto out_free_iova;
+
        INIT_LIST_HEAD(&msi_page->list);
        msi_page->phys = msi_addr;
        msi_page->iova = iova;
        list_add(&msi_page->list, &cookie->msi_page_list);
        return msi_page;
 
+out_free_iova:
+       iommu_dma_free_iova(cookie, iova, size);
 out_free_page:
        kfree(msi_page);
        return NULL;
index 5d0754e..eecd6a4 100644 (file)
@@ -1519,6 +1519,64 @@ static const char *dma_remap_fault_reasons[] =
        "PCE for translation request specifies blocking",
 };
 
+static const char * const dma_remap_sm_fault_reasons[] = {
+       "SM: Invalid Root Table Address",
+       "SM: TTM 0 for request with PASID",
+       "SM: TTM 0 for page group request",
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x33-0x37 */
+       "SM: Error attempting to access Root Entry",
+       "SM: Present bit in Root Entry is clear",
+       "SM: Non-zero reserved field set in Root Entry",
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x3B-0x3F */
+       "SM: Error attempting to access Context Entry",
+       "SM: Present bit in Context Entry is clear",
+       "SM: Non-zero reserved field set in the Context Entry",
+       "SM: Invalid Context Entry",
+       "SM: DTE field in Context Entry is clear",
+       "SM: PASID Enable field in Context Entry is clear",
+       "SM: PASID is larger than the max in Context Entry",
+       "SM: PRE field in Context-Entry is clear",
+       "SM: RID_PASID field error in Context-Entry",
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x49-0x4F */
+       "SM: Error attempting to access the PASID Directory Entry",
+       "SM: Present bit in Directory Entry is clear",
+       "SM: Non-zero reserved field set in PASID Directory Entry",
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x53-0x57 */
+       "SM: Error attempting to access PASID Table Entry",
+       "SM: Present bit in PASID Table Entry is clear",
+       "SM: Non-zero reserved field set in PASID Table Entry",
+       "SM: Invalid Scalable-Mode PASID Table Entry",
+       "SM: ERE field is clear in PASID Table Entry",
+       "SM: SRE field is clear in PASID Table Entry",
+       "Unknown", "Unknown",/* 0x5E-0x5F */
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x60-0x67 */
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x68-0x6F */
+       "SM: Error attempting to access first-level paging entry",
+       "SM: Present bit in first-level paging entry is clear",
+       "SM: Non-zero reserved field set in first-level paging entry",
+       "SM: Error attempting to access FL-PML4 entry",
+       "SM: First-level entry address beyond MGAW in Nested translation",
+       "SM: Read permission error in FL-PML4 entry in Nested translation",
+       "SM: Read permission error in first-level paging entry in Nested translation",
+       "SM: Write permission error in first-level paging entry in Nested translation",
+       "SM: Error attempting to access second-level paging entry",
+       "SM: Read/Write permission error in second-level paging entry",
+       "SM: Non-zero reserved field set in second-level paging entry",
+       "SM: Invalid second-level page table pointer",
+       "SM: A/D bit update needed in second-level entry when set up in no snoop",
+       "Unknown", "Unknown", "Unknown", /* 0x7D-0x7F */
+       "SM: Address in first-level translation is not canonical",
+       "SM: U/S set 0 for first-level translation with user privilege",
+       "SM: No execute permission for request with PASID and ER=1",
+       "SM: Address beyond the DMA hardware max",
+       "SM: Second-level entry address beyond the max",
+       "SM: No write permission for Write/AtomicOp request",
+       "SM: No read permission for Read/AtomicOp request",
+       "SM: Invalid address-interrupt address",
+       "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x88-0x8F */
+       "SM: A/D bit update needed in first-level entry when set up in no snoop",
+};
+
 static const char *irq_remap_fault_reasons[] =
 {
        "Detected reserved fields in the decoded interrupt-remapped request",
@@ -1536,6 +1594,10 @@ static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
                                        ARRAY_SIZE(irq_remap_fault_reasons))) {
                *fault_type = INTR_REMAP;
                return irq_remap_fault_reasons[fault_reason - 0x20];
+       } else if (fault_reason >= 0x30 && (fault_reason - 0x30 <
+                       ARRAY_SIZE(dma_remap_sm_fault_reasons))) {
+               *fault_type = DMA_REMAP;
+               return dma_remap_sm_fault_reasons[fault_reason - 0x30];
        } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
                *fault_type = DMA_REMAP;
                return dma_remap_fault_reasons[fault_reason];
@@ -1611,7 +1673,8 @@ void dmar_msi_read(int irq, struct msi_msg *msg)
 }
 
 static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
-               u8 fault_reason, u16 source_id, unsigned long long addr)
+               u8 fault_reason, int pasid, u16 source_id,
+               unsigned long long addr)
 {
        const char *reason;
        int fault_type;
@@ -1624,10 +1687,11 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
                        PCI_FUNC(source_id & 0xFF), addr >> 48,
                        fault_reason, reason);
        else
-               pr_err("[%s] Request device [%02x:%02x.%d] fault addr %llx [fault reason %02d] %s\n",
+               pr_err("[%s] Request device [%02x:%02x.%d] PASID %x fault addr %llx [fault reason %02d] %s\n",
                       type ? "DMA Read" : "DMA Write",
                       source_id >> 8, PCI_SLOT(source_id & 0xFF),
-                      PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
+                      PCI_FUNC(source_id & 0xFF), pasid, addr,
+                      fault_reason, reason);
        return 0;
 }
 
@@ -1659,8 +1723,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
                u8 fault_reason;
                u16 source_id;
                u64 guest_addr;
-               int type;
+               int type, pasid;
                u32 data;
+               bool pasid_present;
 
                /* highest 32 bits */
                data = readl(iommu->reg + reg +
@@ -1672,10 +1737,12 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
                        fault_reason = dma_frcd_fault_reason(data);
                        type = dma_frcd_type(data);
 
+                       pasid = dma_frcd_pasid_value(data);
                        data = readl(iommu->reg + reg +
                                     fault_index * PRIMARY_FAULT_REG_LEN + 8);
                        source_id = dma_frcd_source_id(data);
 
+                       pasid_present = dma_frcd_pasid_present(data);
                        guest_addr = dmar_readq(iommu->reg + reg +
                                        fault_index * PRIMARY_FAULT_REG_LEN);
                        guest_addr = dma_frcd_page_addr(guest_addr);
@@ -1688,7 +1755,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
                raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
 
                if (!ratelimited)
+                       /* Using pasid -1 if pasid is not present */
                        dmar_fault_do_one(iommu, type, fault_reason,
+                                         pasid_present ? pasid : -1,
                                          source_id, guest_addr);
 
                fault_index++;
index b0c1e5f..9c94e16 100644 (file)
@@ -566,7 +566,7 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
 
 static const struct iommu_ops exynos_iommu_ops;
 
-static int __init exynos_sysmmu_probe(struct platform_device *pdev)
+static int exynos_sysmmu_probe(struct platform_device *pdev)
 {
        int irq, ret;
        struct device *dev = &pdev->dev;
@@ -583,10 +583,8 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev)
                return PTR_ERR(data->sfrbase);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev, "Unable to find IRQ resource\n");
+       if (irq <= 0)
                return irq;
-       }
 
        ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
                                dev_name(dev), data);
@@ -1130,7 +1128,8 @@ static void exynos_iommu_tlb_invalidate_entry(struct exynos_iommu_domain *domain
 }
 
 static size_t exynos_iommu_unmap(struct iommu_domain *iommu_domain,
-                                unsigned long l_iova, size_t size)
+                                unsigned long l_iova, size_t size,
+                                struct iommu_iotlb_gather *gather)
 {
        struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
        sysmmu_iova_t iova = (sysmmu_iova_t)l_iova;
index 2b25d9c..471f05d 100644 (file)
@@ -235,7 +235,7 @@ static void ctx_tbl_walk(struct seq_file *m, struct intel_iommu *iommu, u16 bus)
                tbl_wlk.ctx_entry = context;
                m->private = &tbl_wlk;
 
-               if (pasid_supported(iommu) && is_pasid_enabled(context)) {
+               if (dmar_readq(iommu->reg + DMAR_RTADDR_REG) & DMA_RTADDR_SMT) {
                        pasid_dir_ptr = context->lo & VTD_PAGE_MASK;
                        pasid_dir_size = get_pasid_dir_size(context);
                        pasid_dir_walk(m, pasid_dir_ptr, pasid_dir_size);
index bdaed2d..87de0b9 100644 (file)
 #include <linux/dma-direct.h>
 #include <linux/crash_dump.h>
 #include <linux/numa.h>
+#include <linux/swiotlb.h>
 #include <asm/irq_remapping.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
+#include <trace/events/intel_iommu.h>
 
 #include "irq_remapping.h"
 #include "intel-pasid.h"
@@ -339,11 +341,15 @@ static void domain_exit(struct dmar_domain *domain);
 static void domain_remove_dev_info(struct dmar_domain *domain);
 static void dmar_remove_one_dev_info(struct device *dev);
 static void __dmar_remove_one_dev_info(struct device_domain_info *info);
+static void domain_context_clear(struct intel_iommu *iommu,
+                                struct device *dev);
 static int domain_detach_iommu(struct dmar_domain *domain,
                               struct intel_iommu *iommu);
 static bool device_is_rmrr_locked(struct device *dev);
 static int intel_iommu_attach_device(struct iommu_domain *domain,
                                     struct device *dev);
+static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
+                                           dma_addr_t iova);
 
 #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
 int dmar_disabled = 0;
@@ -360,6 +366,7 @@ static int dmar_forcedac;
 static int intel_iommu_strict;
 static int intel_iommu_superpage = 1;
 static int iommu_identity_mapping;
+static int intel_no_bounce;
 
 #define IDENTMAP_ALL           1
 #define IDENTMAP_GFX           2
@@ -373,6 +380,9 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 static DEFINE_SPINLOCK(device_domain_lock);
 static LIST_HEAD(device_domain_list);
 
+#define device_needs_bounce(d) (!intel_no_bounce && dev_is_pci(d) &&   \
+                               to_pci_dev(d)->untrusted)
+
 /*
  * Iterate over elements in device_domain_list and call the specified
  * callback @fn against each element.
@@ -455,6 +465,9 @@ static int __init intel_iommu_setup(char *str)
                        printk(KERN_INFO
                                "Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n");
                        intel_iommu_tboot_noforce = 1;
+               } else if (!strncmp(str, "nobounce", 8)) {
+                       pr_info("Intel-IOMMU: No bounce buffer. This could expose security risks of DMA attacks\n");
+                       intel_no_bounce = 1;
                }
 
                str += strcspn(str, ",");
@@ -2105,9 +2118,26 @@ out_unlock:
        return ret;
 }
 
+struct domain_context_mapping_data {
+       struct dmar_domain *domain;
+       struct intel_iommu *iommu;
+       struct pasid_table *table;
+};
+
+static int domain_context_mapping_cb(struct pci_dev *pdev,
+                                    u16 alias, void *opaque)
+{
+       struct domain_context_mapping_data *data = opaque;
+
+       return domain_context_mapping_one(data->domain, data->iommu,
+                                         data->table, PCI_BUS_NUM(alias),
+                                         alias & 0xff);
+}
+
 static int
 domain_context_mapping(struct dmar_domain *domain, struct device *dev)
 {
+       struct domain_context_mapping_data data;
        struct pasid_table *table;
        struct intel_iommu *iommu;
        u8 bus, devfn;
@@ -2117,7 +2147,17 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)
                return -ENODEV;
 
        table = intel_pasid_get_table(dev);
-       return domain_context_mapping_one(domain, iommu, table, bus, devfn);
+
+       if (!dev_is_pci(dev))
+               return domain_context_mapping_one(domain, iommu, table,
+                                                 bus, devfn);
+
+       data.domain = domain;
+       data.iommu = iommu;
+       data.table = table;
+
+       return pci_for_each_dma_alias(to_pci_dev(dev),
+                                     &domain_context_mapping_cb, &data);
 }
 
 static int domain_context_mapped_cb(struct pci_dev *pdev,
@@ -3267,7 +3307,7 @@ static int __init init_dmars(void)
                iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
        }
 
-       if (iommu_pass_through)
+       if (iommu_default_passthrough())
                iommu_identity_mapping |= IDENTMAP_ALL;
 
 #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
@@ -3449,6 +3489,7 @@ static bool iommu_need_mapping(struct device *dev)
                                dmar_domain = to_dmar_domain(domain);
                                dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
                        }
+                       dmar_remove_one_dev_info(dev);
                        get_private_domain_for_dev(dev);
                }
 
@@ -3504,6 +3545,9 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
 
        start_paddr = (phys_addr_t)iova_pfn << PAGE_SHIFT;
        start_paddr += paddr & ~PAGE_MASK;
+
+       trace_map_single(dev, start_paddr, paddr, size << VTD_PAGE_SHIFT);
+
        return start_paddr;
 
 error:
@@ -3559,10 +3603,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
        if (dev_is_pci(dev))
                pdev = to_pci_dev(dev);
 
-       dev_dbg(dev, "Device unmapping: pfn %lx-%lx\n", start_pfn, last_pfn);
-
        freelist = domain_unmap(domain, start_pfn, last_pfn);
-
        if (intel_iommu_strict || (pdev && pdev->untrusted) ||
                        !has_iova_flush_queue(&domain->iovad)) {
                iommu_flush_iotlb_psi(iommu, domain, start_pfn,
@@ -3578,6 +3619,8 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
                 * cpu used up by the iotlb flush operation...
                 */
        }
+
+       trace_unmap_single(dev, dev_addr, size);
 }
 
 static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
@@ -3668,6 +3711,8 @@ static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
        }
 
        intel_unmap(dev, startaddr, nrpages << VTD_PAGE_SHIFT);
+
+       trace_unmap_sg(dev, startaddr, nrpages << VTD_PAGE_SHIFT);
 }
 
 static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
@@ -3724,6 +3769,9 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
                return 0;
        }
 
+       trace_map_sg(dev, iova_pfn << PAGE_SHIFT,
+                    sg_phys(sglist), size << VTD_PAGE_SHIFT);
+
        return nelems;
 }
 
@@ -3739,6 +3787,252 @@ static const struct dma_map_ops intel_dma_ops = {
        .dma_supported = dma_direct_supported,
 };
 
+static void
+bounce_sync_single(struct device *dev, dma_addr_t addr, size_t size,
+                  enum dma_data_direction dir, enum dma_sync_target target)
+{
+       struct dmar_domain *domain;
+       phys_addr_t tlb_addr;
+
+       domain = find_domain(dev);
+       if (WARN_ON(!domain))
+               return;
+
+       tlb_addr = intel_iommu_iova_to_phys(&domain->domain, addr);
+       if (is_swiotlb_buffer(tlb_addr))
+               swiotlb_tbl_sync_single(dev, tlb_addr, size, dir, target);
+}
+
+static dma_addr_t
+bounce_map_single(struct device *dev, phys_addr_t paddr, size_t size,
+                 enum dma_data_direction dir, unsigned long attrs,
+                 u64 dma_mask)
+{
+       size_t aligned_size = ALIGN(size, VTD_PAGE_SIZE);
+       struct dmar_domain *domain;
+       struct intel_iommu *iommu;
+       unsigned long iova_pfn;
+       unsigned long nrpages;
+       phys_addr_t tlb_addr;
+       int prot = 0;
+       int ret;
+
+       domain = find_domain(dev);
+       if (WARN_ON(dir == DMA_NONE || !domain))
+               return DMA_MAPPING_ERROR;
+
+       iommu = domain_get_iommu(domain);
+       if (WARN_ON(!iommu))
+               return DMA_MAPPING_ERROR;
+
+       nrpages = aligned_nrpages(0, size);
+       iova_pfn = intel_alloc_iova(dev, domain,
+                                   dma_to_mm_pfn(nrpages), dma_mask);
+       if (!iova_pfn)
+               return DMA_MAPPING_ERROR;
+
+       /*
+        * Check if DMAR supports zero-length reads on write only
+        * mappings..
+        */
+       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL ||
+                       !cap_zlr(iommu->cap))
+               prot |= DMA_PTE_READ;
+       if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+               prot |= DMA_PTE_WRITE;
+
+       /*
+        * If both the physical buffer start address and size are
+        * page aligned, we don't need to use a bounce page.
+        */
+       if (!IS_ALIGNED(paddr | size, VTD_PAGE_SIZE)) {
+               tlb_addr = swiotlb_tbl_map_single(dev,
+                               __phys_to_dma(dev, io_tlb_start),
+                               paddr, size, aligned_size, dir, attrs);
+               if (tlb_addr == DMA_MAPPING_ERROR) {
+                       goto swiotlb_error;
+               } else {
+                       /* Cleanup the padding area. */
+                       void *padding_start = phys_to_virt(tlb_addr);
+                       size_t padding_size = aligned_size;
+
+                       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+                           (dir == DMA_TO_DEVICE ||
+                            dir == DMA_BIDIRECTIONAL)) {
+                               padding_start += size;
+                               padding_size -= size;
+                       }
+
+                       memset(padding_start, 0, padding_size);
+               }
+       } else {
+               tlb_addr = paddr;
+       }
+
+       ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova_pfn),
+                                tlb_addr >> VTD_PAGE_SHIFT, nrpages, prot);
+       if (ret)
+               goto mapping_error;
+
+       trace_bounce_map_single(dev, iova_pfn << PAGE_SHIFT, paddr, size);
+
+       return (phys_addr_t)iova_pfn << PAGE_SHIFT;
+
+mapping_error:
+       if (is_swiotlb_buffer(tlb_addr))
+               swiotlb_tbl_unmap_single(dev, tlb_addr, size,
+                                        aligned_size, dir, attrs);
+swiotlb_error:
+       free_iova_fast(&domain->iovad, iova_pfn, dma_to_mm_pfn(nrpages));
+       dev_err(dev, "Device bounce map: %zx@%llx dir %d --- failed\n",
+               size, (unsigned long long)paddr, dir);
+
+       return DMA_MAPPING_ERROR;
+}
+
+static void
+bounce_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
+                   enum dma_data_direction dir, unsigned long attrs)
+{
+       size_t aligned_size = ALIGN(size, VTD_PAGE_SIZE);
+       struct dmar_domain *domain;
+       phys_addr_t tlb_addr;
+
+       domain = find_domain(dev);
+       if (WARN_ON(!domain))
+               return;
+
+       tlb_addr = intel_iommu_iova_to_phys(&domain->domain, dev_addr);
+       if (WARN_ON(!tlb_addr))
+               return;
+
+       intel_unmap(dev, dev_addr, size);
+       if (is_swiotlb_buffer(tlb_addr))
+               swiotlb_tbl_unmap_single(dev, tlb_addr, size,
+                                        aligned_size, dir, attrs);
+
+       trace_bounce_unmap_single(dev, dev_addr, size);
+}
+
+static dma_addr_t
+bounce_map_page(struct device *dev, struct page *page, unsigned long offset,
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+       return bounce_map_single(dev, page_to_phys(page) + offset,
+                                size, dir, attrs, *dev->dma_mask);
+}
+
+static dma_addr_t
+bounce_map_resource(struct device *dev, phys_addr_t phys_addr, size_t size,
+                   enum dma_data_direction dir, unsigned long attrs)
+{
+       return bounce_map_single(dev, phys_addr, size,
+                                dir, attrs, *dev->dma_mask);
+}
+
+static void
+bounce_unmap_page(struct device *dev, dma_addr_t dev_addr, size_t size,
+                 enum dma_data_direction dir, unsigned long attrs)
+{
+       bounce_unmap_single(dev, dev_addr, size, dir, attrs);
+}
+
+static void
+bounce_unmap_resource(struct device *dev, dma_addr_t dev_addr, size_t size,
+                     enum dma_data_direction dir, unsigned long attrs)
+{
+       bounce_unmap_single(dev, dev_addr, size, dir, attrs);
+}
+
+static void
+bounce_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems,
+               enum dma_data_direction dir, unsigned long attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nelems, i)
+               bounce_unmap_page(dev, sg->dma_address,
+                                 sg_dma_len(sg), dir, attrs);
+}
+
+static int
+bounce_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
+             enum dma_data_direction dir, unsigned long attrs)
+{
+       int i;
+       struct scatterlist *sg;
+
+       for_each_sg(sglist, sg, nelems, i) {
+               sg->dma_address = bounce_map_page(dev, sg_page(sg),
+                                                 sg->offset, sg->length,
+                                                 dir, attrs);
+               if (sg->dma_address == DMA_MAPPING_ERROR)
+                       goto out_unmap;
+               sg_dma_len(sg) = sg->length;
+       }
+
+       return nelems;
+
+out_unmap:
+       bounce_unmap_sg(dev, sglist, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
+       return 0;
+}
+
+static void
+bounce_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
+                          size_t size, enum dma_data_direction dir)
+{
+       bounce_sync_single(dev, addr, size, dir, SYNC_FOR_CPU);
+}
+
+static void
+bounce_sync_single_for_device(struct device *dev, dma_addr_t addr,
+                             size_t size, enum dma_data_direction dir)
+{
+       bounce_sync_single(dev, addr, size, dir, SYNC_FOR_DEVICE);
+}
+
+static void
+bounce_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist,
+                      int nelems, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nelems, i)
+               bounce_sync_single(dev, sg_dma_address(sg),
+                                  sg_dma_len(sg), dir, SYNC_FOR_CPU);
+}
+
+static void
+bounce_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+                         int nelems, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nelems, i)
+               bounce_sync_single(dev, sg_dma_address(sg),
+                                  sg_dma_len(sg), dir, SYNC_FOR_DEVICE);
+}
+
+static const struct dma_map_ops bounce_dma_ops = {
+       .alloc                  = intel_alloc_coherent,
+       .free                   = intel_free_coherent,
+       .map_sg                 = bounce_map_sg,
+       .unmap_sg               = bounce_unmap_sg,
+       .map_page               = bounce_map_page,
+       .unmap_page             = bounce_unmap_page,
+       .sync_single_for_cpu    = bounce_sync_single_for_cpu,
+       .sync_single_for_device = bounce_sync_single_for_device,
+       .sync_sg_for_cpu        = bounce_sync_sg_for_cpu,
+       .sync_sg_for_device     = bounce_sync_sg_for_device,
+       .map_resource           = bounce_map_resource,
+       .unmap_resource         = bounce_unmap_resource,
+       .dma_supported          = dma_direct_supported,
+};
+
 static inline int iommu_domain_cache_init(void)
 {
        int ret = 0;
@@ -4539,22 +4833,20 @@ const struct attribute_group *intel_iommu_groups[] = {
        NULL,
 };
 
-static int __init platform_optin_force_iommu(void)
+static inline bool has_untrusted_dev(void)
 {
        struct pci_dev *pdev = NULL;
-       bool has_untrusted_dev = false;
 
-       if (!dmar_platform_optin() || no_platform_optin)
-               return 0;
+       for_each_pci_dev(pdev)
+               if (pdev->untrusted)
+                       return true;
 
-       for_each_pci_dev(pdev) {
-               if (pdev->untrusted) {
-                       has_untrusted_dev = true;
-                       break;
-               }
-       }
+       return false;
+}
 
-       if (!has_untrusted_dev)
+static int __init platform_optin_force_iommu(void)
+{
+       if (!dmar_platform_optin() || no_platform_optin || !has_untrusted_dev())
                return 0;
 
        if (no_iommu || dmar_disabled)
@@ -4568,9 +4860,6 @@ static int __init platform_optin_force_iommu(void)
                iommu_identity_mapping |= IDENTMAP_ALL;
 
        dmar_disabled = 0;
-#if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB)
-       swiotlb = 0;
-#endif
        no_iommu = 0;
 
        return 1;
@@ -4710,7 +4999,14 @@ int __init intel_iommu_init(void)
        up_write(&dmar_global_lock);
 
 #if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB)
-       swiotlb = 0;
+       /*
+        * If the system has no untrusted device or the user has decided
+        * to disable the bounce page mechanisms, we don't need swiotlb.
+        * Mark this and the pre-allocated bounce pages will be released
+        * later.
+        */
+       if (!has_untrusted_dev() || intel_no_bounce)
+               swiotlb = 0;
 #endif
        dma_ops = &intel_dma_ops;
 
@@ -4758,6 +5054,28 @@ out_free_dmar:
        return ret;
 }
 
+static int domain_context_clear_one_cb(struct pci_dev *pdev, u16 alias, void *opaque)
+{
+       struct intel_iommu *iommu = opaque;
+
+       domain_context_clear_one(iommu, PCI_BUS_NUM(alias), alias & 0xff);
+       return 0;
+}
+
+/*
+ * NB - intel-iommu lacks any sort of reference counting for the users of
+ * dependent devices.  If multiple endpoints have intersecting dependent
+ * devices, unbinding the driver from any one of them will possibly leave
+ * the others unable to operate.
+ */
+static void domain_context_clear(struct intel_iommu *iommu, struct device *dev)
+{
+       if (!iommu || !dev || !dev_is_pci(dev))
+               return;
+
+       pci_for_each_dma_alias(to_pci_dev(dev), &domain_context_clear_one_cb, iommu);
+}
+
 static void __dmar_remove_one_dev_info(struct device_domain_info *info)
 {
        struct dmar_domain *domain;
@@ -4778,7 +5096,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
                                        PASID_RID2PASID);
 
                iommu_disable_dev_iotlb(info);
-               domain_context_clear_one(iommu, info->bus, info->devfn);
+               domain_context_clear(iommu, info->dev);
                intel_pasid_free_table(info->dev);
        }
 
@@ -4790,7 +5108,8 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
 
        /* free the private domain */
        if (domain->flags & DOMAIN_FLAG_LOSE_CHILDREN &&
-           !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY))
+           !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
+           list_empty(&domain->devices))
                domain_exit(info->domain);
 
        free_devinfo_mem(info);
@@ -4803,7 +5122,8 @@ static void dmar_remove_one_dev_info(struct device *dev)
 
        spin_lock_irqsave(&device_domain_lock, flags);
        info = dev->archdata.iommu;
-       __dmar_remove_one_dev_info(info);
+       if (info)
+               __dmar_remove_one_dev_info(info);
        spin_unlock_irqrestore(&device_domain_lock, flags);
 }
 
@@ -5150,7 +5470,8 @@ static int intel_iommu_map(struct iommu_domain *domain,
 }
 
 static size_t intel_iommu_unmap(struct iommu_domain *domain,
-                               unsigned long iova, size_t size)
+                               unsigned long iova, size_t size,
+                               struct iommu_iotlb_gather *gather)
 {
        struct dmar_domain *dmar_domain = to_dmar_domain(domain);
        struct page *freelist = NULL;
@@ -5281,6 +5602,7 @@ static int intel_iommu_add_device(struct device *dev)
                if (device_def_domain_type(dev) == IOMMU_DOMAIN_IDENTITY) {
                        ret = iommu_request_dm_for_dev(dev);
                        if (ret) {
+                               dmar_remove_one_dev_info(dev);
                                dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
                                domain_add_dev_info(si_domain, dev);
                                dev_info(dev,
@@ -5291,6 +5613,7 @@ static int intel_iommu_add_device(struct device *dev)
                if (device_def_domain_type(dev) == IOMMU_DOMAIN_DMA) {
                        ret = iommu_request_dma_domain_for_dev(dev);
                        if (ret) {
+                               dmar_remove_one_dev_info(dev);
                                dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
                                if (!get_private_domain_for_dev(dev)) {
                                        dev_warn(dev,
@@ -5304,6 +5627,11 @@ static int intel_iommu_add_device(struct device *dev)
                }
        }
 
+       if (device_needs_bounce(dev)) {
+               dev_info(dev, "Use Intel IOMMU bounce page dma_ops\n");
+               set_dma_ops(dev, &bounce_dma_ops);
+       }
+
        return 0;
 }
 
@@ -5316,9 +5644,14 @@ static void intel_iommu_remove_device(struct device *dev)
        if (!iommu)
                return;
 
+       dmar_remove_one_dev_info(dev);
+
        iommu_group_remove_device(dev);
 
        iommu_device_unlink(&iommu->iommu, dev);
+
+       if (device_needs_bounce(dev))
+               set_dma_ops(dev, NULL);
 }
 
 static void intel_iommu_get_resv_regions(struct device *device,
@@ -5632,20 +5965,46 @@ const struct iommu_ops intel_iommu_ops = {
        .pgsize_bitmap          = INTEL_IOMMU_PGSIZES,
 };
 
-static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
+static void quirk_iommu_igfx(struct pci_dev *dev)
 {
-       /* G4x/GM45 integrated gfx dmar support is totally busted. */
        pci_info(dev, "Disabling IOMMU for graphics on this chipset\n");
        dmar_map_gfx = 0;
 }
 
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
+/* G4x/GM45 integrated gfx dmar support is totally busted. */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx);
+
+/* Broadwell igfx malfunctions with dmar */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160E, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1602, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160A, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160D, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1616, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161B, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161E, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1612, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161A, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161D, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1626, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162B, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162E, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1622, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162A, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162D, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1636, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163B, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163E, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx);
 
 static void quirk_iommu_rwbf(struct pci_dev *dev)
 {
index 780de0c..9b15913 100644 (file)
@@ -100,24 +100,19 @@ int intel_svm_finish_prq(struct intel_iommu *iommu)
 }
 
 static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_dev *sdev,
-                                      unsigned long address, unsigned long pages, int ih, int gl)
+                               unsigned long address, unsigned long pages, int ih)
 {
        struct qi_desc desc;
 
-       if (pages == -1) {
-               /* For global kernel pages we have to flush them in *all* PASIDs
-                * because that's the only option the hardware gives us. Despite
-                * the fact that they are actually only accessible through one. */
-               if (gl)
-                       desc.qw0 = QI_EIOTLB_PASID(svm->pasid) |
-                                       QI_EIOTLB_DID(sdev->did) |
-                                       QI_EIOTLB_GRAN(QI_GRAN_ALL_ALL) |
-                                       QI_EIOTLB_TYPE;
-               else
-                       desc.qw0 = QI_EIOTLB_PASID(svm->pasid) |
-                                       QI_EIOTLB_DID(sdev->did) |
-                                       QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
-                                       QI_EIOTLB_TYPE;
+       /*
+        * Do PASID granu IOTLB invalidation if page selective capability is
+        * not available.
+        */
+       if (pages == -1 || !cap_pgsel_inv(svm->iommu->cap)) {
+               desc.qw0 = QI_EIOTLB_PASID(svm->pasid) |
+                       QI_EIOTLB_DID(sdev->did) |
+                       QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
+                       QI_EIOTLB_TYPE;
                desc.qw1 = 0;
        } else {
                int mask = ilog2(__roundup_pow_of_two(pages));
@@ -127,7 +122,6 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
                                QI_EIOTLB_GRAN(QI_GRAN_PSI_PASID) |
                                QI_EIOTLB_TYPE;
                desc.qw1 = QI_EIOTLB_ADDR(address) |
-                               QI_EIOTLB_GL(gl) |
                                QI_EIOTLB_IH(ih) |
                                QI_EIOTLB_AM(mask);
        }
@@ -162,13 +156,13 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
 }
 
 static void intel_flush_svm_range(struct intel_svm *svm, unsigned long address,
-                                 unsigned long pages, int ih, int gl)
+                               unsigned long pages, int ih)
 {
        struct intel_svm_dev *sdev;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdev, &svm->devs, list)
-               intel_flush_svm_range_dev(svm, sdev, address, pages, ih, gl);
+               intel_flush_svm_range_dev(svm, sdev, address, pages, ih);
        rcu_read_unlock();
 }
 
@@ -180,7 +174,7 @@ static void intel_invalidate_range(struct mmu_notifier *mn,
        struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
 
        intel_flush_svm_range(svm, start,
-                             (end - start + PAGE_SIZE - 1) >> VTD_PAGE_SHIFT, 0, 0);
+                             (end - start + PAGE_SIZE - 1) >> VTD_PAGE_SHIFT, 0);
 }
 
 static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -203,7 +197,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
        rcu_read_lock();
        list_for_each_entry_rcu(sdev, &svm->devs, list) {
                intel_pasid_tear_down_entry(svm->iommu, sdev->dev, svm->pasid);
-               intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
+               intel_flush_svm_range_dev(svm, sdev, 0, -1, 0);
        }
        rcu_read_unlock();
 
@@ -425,7 +419,7 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
                                 * large and has to be physically contiguous. So it's
                                 * hard to be as defensive as we might like. */
                                intel_pasid_tear_down_entry(iommu, dev, svm->pasid);
-                               intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
+                               intel_flush_svm_range_dev(svm, sdev, 0, -1, 0);
                                kfree_rcu(sdev, rcu);
 
                                if (list_empty(&svm->devs)) {
diff --git a/drivers/iommu/intel-trace.c b/drivers/iommu/intel-trace.c
new file mode 100644 (file)
index 0000000..bfb6a6e
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel IOMMU trace support
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_iommu.h>
index 4786ca0..81e43c1 100644 (file)
@@ -376,13 +376,13 @@ static int set_msi_sid_cb(struct pci_dev *pdev, u16 alias, void *opaque)
 {
        struct set_msi_sid_data *data = opaque;
 
+       if (data->count == 0 || PCI_BUS_NUM(alias) == PCI_BUS_NUM(data->alias))
+               data->busmatch_count++;
+
        data->pdev = pdev;
        data->alias = alias;
        data->count++;
 
-       if (PCI_BUS_NUM(alias) == pdev->bus->number)
-               data->busmatch_count++;
-
        return 0;
 }
 
index 0fc8dfa..4cb3949 100644 (file)
 #define ARM_V7S_TEX_MASK               0x7
 #define ARM_V7S_ATTR_TEX(val)          (((val) & ARM_V7S_TEX_MASK) << ARM_V7S_TEX_SHIFT)
 
-#define ARM_V7S_ATTR_MTK_4GB           BIT(9) /* MTK extend it for 4GB mode */
+/* MediaTek extend the two bits for PA 32bit/33bit */
+#define ARM_V7S_ATTR_MTK_PA_BIT32      BIT(9)
+#define ARM_V7S_ATTR_MTK_PA_BIT33      BIT(4)
 
 /* *well, except for TEX on level 2 large pages, of course :( */
 #define ARM_V7S_CONT_PAGE_TEX_SHIFT    6
@@ -169,18 +171,62 @@ struct arm_v7s_io_pgtable {
        spinlock_t              split_lock;
 };
 
+static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl);
+
 static dma_addr_t __arm_v7s_dma_addr(void *pages)
 {
        return (dma_addr_t)virt_to_phys(pages);
 }
 
-static arm_v7s_iopte *iopte_deref(arm_v7s_iopte pte, int lvl)
+static bool arm_v7s_is_mtk_enabled(struct io_pgtable_cfg *cfg)
+{
+       return IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT) &&
+               (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_EXT);
+}
+
+static arm_v7s_iopte paddr_to_iopte(phys_addr_t paddr, int lvl,
+                                   struct io_pgtable_cfg *cfg)
+{
+       arm_v7s_iopte pte = paddr & ARM_V7S_LVL_MASK(lvl);
+
+       if (!arm_v7s_is_mtk_enabled(cfg))
+               return pte;
+
+       if (paddr & BIT_ULL(32))
+               pte |= ARM_V7S_ATTR_MTK_PA_BIT32;
+       if (paddr & BIT_ULL(33))
+               pte |= ARM_V7S_ATTR_MTK_PA_BIT33;
+       return pte;
+}
+
+static phys_addr_t iopte_to_paddr(arm_v7s_iopte pte, int lvl,
+                                 struct io_pgtable_cfg *cfg)
 {
+       arm_v7s_iopte mask;
+       phys_addr_t paddr;
+
        if (ARM_V7S_PTE_IS_TABLE(pte, lvl))
-               pte &= ARM_V7S_TABLE_MASK;
+               mask = ARM_V7S_TABLE_MASK;
+       else if (arm_v7s_pte_is_cont(pte, lvl))
+               mask = ARM_V7S_LVL_MASK(lvl) * ARM_V7S_CONT_PAGES;
        else
-               pte &= ARM_V7S_LVL_MASK(lvl);
-       return phys_to_virt(pte);
+               mask = ARM_V7S_LVL_MASK(lvl);
+
+       paddr = pte & mask;
+       if (!arm_v7s_is_mtk_enabled(cfg))
+               return paddr;
+
+       if (pte & ARM_V7S_ATTR_MTK_PA_BIT32)
+               paddr |= BIT_ULL(32);
+       if (pte & ARM_V7S_ATTR_MTK_PA_BIT33)
+               paddr |= BIT_ULL(33);
+       return paddr;
+}
+
+static arm_v7s_iopte *iopte_deref(arm_v7s_iopte pte, int lvl,
+                                 struct arm_v7s_io_pgtable *data)
+{
+       return phys_to_virt(iopte_to_paddr(pte, lvl, &data->iop.cfg));
 }
 
 static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
@@ -295,9 +341,6 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl,
        if (lvl == 1 && (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS))
                pte |= ARM_V7S_ATTR_NS_SECTION;
 
-       if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB)
-               pte |= ARM_V7S_ATTR_MTK_4GB;
-
        return pte;
 }
 
@@ -362,7 +405,8 @@ static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl)
        return false;
 }
 
-static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long,
+static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *,
+                             struct iommu_iotlb_gather *, unsigned long,
                              size_t, int, arm_v7s_iopte *);
 
 static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
@@ -383,7 +427,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
                        size_t sz = ARM_V7S_BLOCK_SIZE(lvl);
 
                        tblp = ptep - ARM_V7S_LVL_IDX(iova, lvl);
-                       if (WARN_ON(__arm_v7s_unmap(data, iova + i * sz,
+                       if (WARN_ON(__arm_v7s_unmap(data, NULL, iova + i * sz,
                                                    sz, lvl, tblp) != sz))
                                return -EINVAL;
                } else if (ptep[i]) {
@@ -396,7 +440,7 @@ static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
        if (num_entries > 1)
                pte = arm_v7s_pte_to_cont(pte, lvl);
 
-       pte |= paddr & ARM_V7S_LVL_MASK(lvl);
+       pte |= paddr_to_iopte(paddr, lvl, cfg);
 
        __arm_v7s_set_pte(ptep, pte, num_entries, cfg);
        return 0;
@@ -462,7 +506,7 @@ static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova,
        }
 
        if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) {
-               cptep = iopte_deref(pte, lvl);
+               cptep = iopte_deref(pte, lvl, data);
        } else if (pte) {
                /* We require an unmap first */
                WARN_ON(!selftest_running);
@@ -484,7 +528,8 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova,
        if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
                return 0;
 
-       if (WARN_ON(upper_32_bits(iova) || upper_32_bits(paddr)))
+       if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias) ||
+                   paddr >= (1ULL << data->iop.cfg.oas)))
                return -ERANGE;
 
        ret = __arm_v7s_map(data, iova, paddr, size, prot, 1, data->pgd);
@@ -493,9 +538,8 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova,
         * a chance for anything to kick off a table walk for the new iova.
         */
        if (iop->cfg.quirks & IO_PGTABLE_QUIRK_TLBI_ON_MAP) {
-               io_pgtable_tlb_add_flush(iop, iova, size,
-                                        ARM_V7S_BLOCK_SIZE(2), false);
-               io_pgtable_tlb_sync(iop);
+               io_pgtable_tlb_flush_walk(iop, iova, size,
+                                         ARM_V7S_BLOCK_SIZE(2));
        } else {
                wmb();
        }
@@ -512,7 +556,8 @@ static void arm_v7s_free_pgtable(struct io_pgtable *iop)
                arm_v7s_iopte pte = data->pgd[i];
 
                if (ARM_V7S_PTE_IS_TABLE(pte, 1))
-                       __arm_v7s_free_table(iopte_deref(pte, 1), 2, data);
+                       __arm_v7s_free_table(iopte_deref(pte, 1, data),
+                                            2, data);
        }
        __arm_v7s_free_table(data->pgd, 1, data);
        kmem_cache_destroy(data->l2_tables);
@@ -541,12 +586,12 @@ static arm_v7s_iopte arm_v7s_split_cont(struct arm_v7s_io_pgtable *data,
        __arm_v7s_pte_sync(ptep, ARM_V7S_CONT_PAGES, &iop->cfg);
 
        size *= ARM_V7S_CONT_PAGES;
-       io_pgtable_tlb_add_flush(iop, iova, size, size, true);
-       io_pgtable_tlb_sync(iop);
+       io_pgtable_tlb_flush_leaf(iop, iova, size, size);
        return pte;
 }
 
 static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
+                                     struct iommu_iotlb_gather *gather,
                                      unsigned long iova, size_t size,
                                      arm_v7s_iopte blk_pte,
                                      arm_v7s_iopte *ptep)
@@ -582,16 +627,16 @@ static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
                if (!ARM_V7S_PTE_IS_TABLE(pte, 1))
                        return 0;
 
-               tablep = iopte_deref(pte, 1);
-               return __arm_v7s_unmap(data, iova, size, 2, tablep);
+               tablep = iopte_deref(pte, 1, data);
+               return __arm_v7s_unmap(data, gather, iova, size, 2, tablep);
        }
 
-       io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
-       io_pgtable_tlb_sync(&data->iop);
+       io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
        return size;
 }
 
 static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
+                             struct iommu_iotlb_gather *gather,
                              unsigned long iova, size_t size, int lvl,
                              arm_v7s_iopte *ptep)
 {
@@ -638,10 +683,9 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
                for (i = 0; i < num_entries; i++) {
                        if (ARM_V7S_PTE_IS_TABLE(pte[i], lvl)) {
                                /* Also flush any partial walks */
-                               io_pgtable_tlb_add_flush(iop, iova, blk_size,
-                                       ARM_V7S_BLOCK_SIZE(lvl + 1), false);
-                               io_pgtable_tlb_sync(iop);
-                               ptep = iopte_deref(pte[i], lvl);
+                               io_pgtable_tlb_flush_walk(iop, iova, blk_size,
+                                               ARM_V7S_BLOCK_SIZE(lvl + 1));
+                               ptep = iopte_deref(pte[i], lvl, data);
                                __arm_v7s_free_table(ptep, lvl + 1, data);
                        } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {
                                /*
@@ -651,8 +695,7 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
                                 */
                                smp_wmb();
                        } else {
-                               io_pgtable_tlb_add_flush(iop, iova, blk_size,
-                                                        blk_size, true);
+                               io_pgtable_tlb_add_page(iop, gather, iova, blk_size);
                        }
                        iova += blk_size;
                }
@@ -662,23 +705,24 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
                 * Insert a table at the next level to map the old region,
                 * minus the part we want to unmap
                 */
-               return arm_v7s_split_blk_unmap(data, iova, size, pte[0], ptep);
+               return arm_v7s_split_blk_unmap(data, gather, iova, size, pte[0],
+                                              ptep);
        }
 
        /* Keep on walkin' */
-       ptep = iopte_deref(pte[0], lvl);
-       return __arm_v7s_unmap(data, iova, size, lvl + 1, ptep);
+       ptep = iopte_deref(pte[0], lvl, data);
+       return __arm_v7s_unmap(data, gather, iova, size, lvl + 1, ptep);
 }
 
 static size_t arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
-                           size_t size)
+                           size_t size, struct iommu_iotlb_gather *gather)
 {
        struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);
 
        if (WARN_ON(upper_32_bits(iova)))
                return 0;
 
-       return __arm_v7s_unmap(data, iova, size, 1, data->pgd);
+       return __arm_v7s_unmap(data, gather, iova, size, 1, data->pgd);
 }
 
 static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
@@ -692,7 +736,7 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
        do {
                ptep += ARM_V7S_LVL_IDX(iova, ++lvl);
                pte = READ_ONCE(*ptep);
-               ptep = iopte_deref(pte, lvl);
+               ptep = iopte_deref(pte, lvl, data);
        } while (ARM_V7S_PTE_IS_TABLE(pte, lvl));
 
        if (!ARM_V7S_PTE_IS_VALID(pte))
@@ -701,7 +745,7 @@ static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
        mask = ARM_V7S_LVL_MASK(lvl);
        if (arm_v7s_pte_is_cont(pte, lvl))
                mask *= ARM_V7S_CONT_PAGES;
-       return (pte & mask) | (iova & ~mask);
+       return iopte_to_paddr(pte, lvl, &data->iop.cfg) | (iova & ~mask);
 }
 
 static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
@@ -709,18 +753,21 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
 {
        struct arm_v7s_io_pgtable *data;
 
-       if (cfg->ias > ARM_V7S_ADDR_BITS || cfg->oas > ARM_V7S_ADDR_BITS)
+       if (cfg->ias > ARM_V7S_ADDR_BITS)
+               return NULL;
+
+       if (cfg->oas > (arm_v7s_is_mtk_enabled(cfg) ? 34 : ARM_V7S_ADDR_BITS))
                return NULL;
 
        if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
                            IO_PGTABLE_QUIRK_NO_PERMS |
                            IO_PGTABLE_QUIRK_TLBI_ON_MAP |
-                           IO_PGTABLE_QUIRK_ARM_MTK_4GB |
+                           IO_PGTABLE_QUIRK_ARM_MTK_EXT |
                            IO_PGTABLE_QUIRK_NON_STRICT))
                return NULL;
 
        /* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */
-       if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_4GB &&
+       if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_MTK_EXT &&
            !(cfg->quirks & IO_PGTABLE_QUIRK_NO_PERMS))
                        return NULL;
 
@@ -806,22 +853,24 @@ static void dummy_tlb_flush_all(void *cookie)
        WARN_ON(cookie != cfg_cookie);
 }
 
-static void dummy_tlb_add_flush(unsigned long iova, size_t size,
-                               size_t granule, bool leaf, void *cookie)
+static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule,
+                           void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
        WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
 }
 
-static void dummy_tlb_sync(void *cookie)
+static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
+                              unsigned long iova, size_t granule, void *cookie)
 {
-       WARN_ON(cookie != cfg_cookie);
+       dummy_tlb_flush(iova, granule, granule, cookie);
 }
 
-static const struct iommu_gather_ops dummy_tlb_ops = {
+static const struct iommu_flush_ops dummy_tlb_ops = {
        .tlb_flush_all  = dummy_tlb_flush_all,
-       .tlb_add_flush  = dummy_tlb_add_flush,
-       .tlb_sync       = dummy_tlb_sync,
+       .tlb_flush_walk = dummy_tlb_flush,
+       .tlb_flush_leaf = dummy_tlb_flush,
+       .tlb_add_page   = dummy_tlb_add_page,
 };
 
 #define __FAIL(ops)    ({                              \
@@ -896,7 +945,7 @@ static int __init arm_v7s_do_selftests(void)
        size = 1UL << __ffs(cfg.pgsize_bitmap);
        while (i < loopnr) {
                iova_start = i * SZ_16M;
-               if (ops->unmap(ops, iova_start + size, size) != size)
+               if (ops->unmap(ops, iova_start + size, size, NULL) != size)
                        return __FAIL(ops);
 
                /* Remap of partial unmap */
@@ -914,7 +963,7 @@ static int __init arm_v7s_do_selftests(void)
        for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) {
                size = 1UL << i;
 
-               if (ops->unmap(ops, iova, size) != size)
+               if (ops->unmap(ops, iova, size, NULL) != size)
                        return __FAIL(ops);
 
                if (ops->iova_to_phys(ops, iova + 42))
index 161a7d5..4c91359 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/atomic.h>
 #include <linux/bitops.h>
 #include <linux/io-pgtable.h>
-#include <linux/iommu.h>
 #include <linux/kernel.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -290,6 +289,7 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte,
 }
 
 static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
+                              struct iommu_iotlb_gather *gather,
                               unsigned long iova, size_t size, int lvl,
                               arm_lpae_iopte *ptep);
 
@@ -335,8 +335,10 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
                size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data);
 
                tblp = ptep - ARM_LPAE_LVL_IDX(iova, lvl, data);
-               if (WARN_ON(__arm_lpae_unmap(data, iova, sz, lvl, tblp) != sz))
+               if (__arm_lpae_unmap(data, NULL, iova, sz, lvl, tblp) != sz) {
+                       WARN_ON(1);
                        return -EINVAL;
+               }
        }
 
        __arm_lpae_init_pte(data, paddr, prot, lvl, ptep);
@@ -537,6 +539,7 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop)
 }
 
 static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
+                                      struct iommu_iotlb_gather *gather,
                                       unsigned long iova, size_t size,
                                       arm_lpae_iopte blk_pte, int lvl,
                                       arm_lpae_iopte *ptep)
@@ -582,15 +585,15 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
 
                tablep = iopte_deref(pte, data);
        } else if (unmap_idx >= 0) {
-               io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
-               io_pgtable_tlb_sync(&data->iop);
+               io_pgtable_tlb_add_page(&data->iop, gather, iova, size);
                return size;
        }
 
-       return __arm_lpae_unmap(data, iova, size, lvl, tablep);
+       return __arm_lpae_unmap(data, gather, iova, size, lvl, tablep);
 }
 
 static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
+                              struct iommu_iotlb_gather *gather,
                               unsigned long iova, size_t size, int lvl,
                               arm_lpae_iopte *ptep)
 {
@@ -612,9 +615,8 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
 
                if (!iopte_leaf(pte, lvl, iop->fmt)) {
                        /* Also flush any partial walks */
-                       io_pgtable_tlb_add_flush(iop, iova, size,
-                                               ARM_LPAE_GRANULE(data), false);
-                       io_pgtable_tlb_sync(iop);
+                       io_pgtable_tlb_flush_walk(iop, iova, size,
+                                                 ARM_LPAE_GRANULE(data));
                        ptep = iopte_deref(pte, data);
                        __arm_lpae_free_pgtable(data, lvl + 1, ptep);
                } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {
@@ -625,7 +627,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
                         */
                        smp_wmb();
                } else {
-                       io_pgtable_tlb_add_flush(iop, iova, size, size, true);
+                       io_pgtable_tlb_add_page(iop, gather, iova, size);
                }
 
                return size;
@@ -634,17 +636,17 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
                 * Insert a table at the next level to map the old region,
                 * minus the part we want to unmap
                 */
-               return arm_lpae_split_blk_unmap(data, iova, size, pte,
+               return arm_lpae_split_blk_unmap(data, gather, iova, size, pte,
                                                lvl + 1, ptep);
        }
 
        /* Keep on walkin' */
        ptep = iopte_deref(pte, data);
-       return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep);
+       return __arm_lpae_unmap(data, gather, iova, size, lvl + 1, ptep);
 }
 
 static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
-                            size_t size)
+                            size_t size, struct iommu_iotlb_gather *gather)
 {
        struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
        arm_lpae_iopte *ptep = data->pgd;
@@ -653,7 +655,7 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
        if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias)))
                return 0;
 
-       return __arm_lpae_unmap(data, iova, size, lvl, ptep);
+       return __arm_lpae_unmap(data, gather, iova, size, lvl, ptep);
 }
 
 static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
@@ -1070,22 +1072,24 @@ static void dummy_tlb_flush_all(void *cookie)
        WARN_ON(cookie != cfg_cookie);
 }
 
-static void dummy_tlb_add_flush(unsigned long iova, size_t size,
-                               size_t granule, bool leaf, void *cookie)
+static void dummy_tlb_flush(unsigned long iova, size_t size, size_t granule,
+                           void *cookie)
 {
        WARN_ON(cookie != cfg_cookie);
        WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
 }
 
-static void dummy_tlb_sync(void *cookie)
+static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
+                              unsigned long iova, size_t granule, void *cookie)
 {
-       WARN_ON(cookie != cfg_cookie);
+       dummy_tlb_flush(iova, granule, granule, cookie);
 }
 
-static const struct iommu_gather_ops dummy_tlb_ops __initconst = {
+static const struct iommu_flush_ops dummy_tlb_ops __initconst = {
        .tlb_flush_all  = dummy_tlb_flush_all,
-       .tlb_add_flush  = dummy_tlb_add_flush,
-       .tlb_sync       = dummy_tlb_sync,
+       .tlb_flush_walk = dummy_tlb_flush,
+       .tlb_flush_leaf = dummy_tlb_flush,
+       .tlb_add_page   = dummy_tlb_add_page,
 };
 
 static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops)
@@ -1168,7 +1172,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
 
                /* Partial unmap */
                size = 1UL << __ffs(cfg->pgsize_bitmap);
-               if (ops->unmap(ops, SZ_1G + size, size) != size)
+               if (ops->unmap(ops, SZ_1G + size, size, NULL) != size)
                        return __FAIL(ops, i);
 
                /* Remap of partial unmap */
@@ -1183,7 +1187,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
                for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) {
                        size = 1UL << j;
 
-                       if (ops->unmap(ops, iova, size) != size)
+                       if (ops->unmap(ops, iova, size, NULL) != size)
                                return __FAIL(ops, i);
 
                        if (ops->iova_to_phys(ops, iova + 42))
index 0c674d8..d658c7c 100644 (file)
 
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
-#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH
-static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY;
-#else
-static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA;
-#endif
+
+static unsigned int iommu_def_domain_type __read_mostly;
 static bool iommu_dma_strict __read_mostly = true;
+static u32 iommu_cmd_line __read_mostly;
 
 struct iommu_group {
        struct kobject kobj;
@@ -68,6 +66,18 @@ static const char * const iommu_group_resv_type_string[] = {
        [IOMMU_RESV_SW_MSI]                     = "msi",
 };
 
+#define IOMMU_CMD_LINE_DMA_API         BIT(0)
+
+static void iommu_set_cmd_line_dma_api(void)
+{
+       iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;
+}
+
+static bool iommu_cmd_line_dma_api(void)
+{
+       return !!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API);
+}
+
 #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)          \
 struct iommu_group_attribute iommu_group_attr_##_name =                \
        __ATTR(_name, _mode, _show, _store)
@@ -80,12 +90,55 @@ struct iommu_group_attribute iommu_group_attr_##_name =             \
 static LIST_HEAD(iommu_device_list);
 static DEFINE_SPINLOCK(iommu_device_lock);
 
+/*
+ * Use a function instead of an array here because the domain-type is a
+ * bit-field, so an array would waste memory.
+ */
+static const char *iommu_domain_type_str(unsigned int t)
+{
+       switch (t) {
+       case IOMMU_DOMAIN_BLOCKED:
+               return "Blocked";
+       case IOMMU_DOMAIN_IDENTITY:
+               return "Passthrough";
+       case IOMMU_DOMAIN_UNMANAGED:
+               return "Unmanaged";
+       case IOMMU_DOMAIN_DMA:
+               return "Translated";
+       default:
+               return "Unknown";
+       }
+}
+
+static int __init iommu_subsys_init(void)
+{
+       bool cmd_line = iommu_cmd_line_dma_api();
+
+       if (!cmd_line) {
+               if (IS_ENABLED(CONFIG_IOMMU_DEFAULT_PASSTHROUGH))
+                       iommu_set_default_passthrough(false);
+               else
+                       iommu_set_default_translated(false);
+
+               if (iommu_default_passthrough() && mem_encrypt_active()) {
+                       pr_info("Memory encryption detected - Disabling default IOMMU Passthrough\n");
+                       iommu_set_default_translated(false);
+               }
+       }
+
+       pr_info("Default domain type: %s %s\n",
+               iommu_domain_type_str(iommu_def_domain_type),
+               cmd_line ? "(set via kernel command line)" : "");
+
+       return 0;
+}
+subsys_initcall(iommu_subsys_init);
+
 int iommu_device_register(struct iommu_device *iommu)
 {
        spin_lock(&iommu_device_lock);
        list_add_tail(&iommu->list, &iommu_device_list);
        spin_unlock(&iommu_device_lock);
-
        return 0;
 }
 
@@ -165,7 +218,11 @@ static int __init iommu_set_def_domain_type(char *str)
        if (ret)
                return ret;
 
-       iommu_def_domain_type = pt ? IOMMU_DOMAIN_IDENTITY : IOMMU_DOMAIN_DMA;
+       if (pt)
+               iommu_set_default_passthrough(true);
+       else
+               iommu_set_default_translated(true);
+
        return 0;
 }
 early_param("iommu.passthrough", iommu_set_def_domain_type);
@@ -229,60 +286,58 @@ static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf)
  * @new: new region to insert
  * @regions: list of regions
  *
- * The new element is sorted by address with respect to the other
- * regions of the same type. In case it overlaps with another
- * region of the same type, regions are merged. In case it
- * overlaps with another region of different type, regions are
- * not merged.
+ * Elements are sorted by start address and overlapping segments
+ * of the same type are merged.
  */
-static int iommu_insert_resv_region(struct iommu_resv_region *new,
-                                   struct list_head *regions)
+int iommu_insert_resv_region(struct iommu_resv_region *new,
+                            struct list_head *regions)
 {
-       struct iommu_resv_region *region;
-       phys_addr_t start = new->start;
-       phys_addr_t end = new->start + new->length - 1;
-       struct list_head *pos = regions->next;
-
-       while (pos != regions) {
-               struct iommu_resv_region *entry =
-                       list_entry(pos, struct iommu_resv_region, list);
-               phys_addr_t a = entry->start;
-               phys_addr_t b = entry->start + entry->length - 1;
-               int type = entry->type;
-
-               if (end < a) {
-                       goto insert;
-               } else if (start > b) {
-                       pos = pos->next;
-               } else if ((start >= a) && (end <= b)) {
-                       if (new->type == type)
-                               return 0;
-                       else
-                               pos = pos->next;
+       struct iommu_resv_region *iter, *tmp, *nr, *top;
+       LIST_HEAD(stack);
+
+       nr = iommu_alloc_resv_region(new->start, new->length,
+                                    new->prot, new->type);
+       if (!nr)
+               return -ENOMEM;
+
+       /* First add the new element based on start address sorting */
+       list_for_each_entry(iter, regions, list) {
+               if (nr->start < iter->start ||
+                   (nr->start == iter->start && nr->type <= iter->type))
+                       break;
+       }
+       list_add_tail(&nr->list, &iter->list);
+
+       /* Merge overlapping segments of type nr->type in @regions, if any */
+       list_for_each_entry_safe(iter, tmp, regions, list) {
+               phys_addr_t top_end, iter_end = iter->start + iter->length - 1;
+
+               /* no merge needed on elements of different types than @nr */
+               if (iter->type != nr->type) {
+                       list_move_tail(&iter->list, &stack);
+                       continue;
+               }
+
+               /* look for the last stack element of same type as @iter */
+               list_for_each_entry_reverse(top, &stack, list)
+                       if (top->type == iter->type)
+                               goto check_overlap;
+
+               list_move_tail(&iter->list, &stack);
+               continue;
+
+check_overlap:
+               top_end = top->start + top->length - 1;
+
+               if (iter->start > top_end + 1) {
+                       list_move_tail(&iter->list, &stack);
                } else {
-                       if (new->type == type) {
-                               phys_addr_t new_start = min(a, start);
-                               phys_addr_t new_end = max(b, end);
-                               int ret;
-
-                               list_del(&entry->list);
-                               entry->start = new_start;
-                               entry->length = new_end - new_start + 1;
-                               ret = iommu_insert_resv_region(entry, regions);
-                               kfree(entry);
-                               return ret;
-                       } else {
-                               pos = pos->next;
-                       }
+                       top->length = max(top_end, iter_end) - top->start + 1;
+                       list_del(&iter->list);
+                       kfree(iter);
                }
        }
-insert:
-       region = iommu_alloc_resv_region(new->start, new->length,
-                                        new->prot, new->type);
-       if (!region)
-               return -ENOMEM;
-
-       list_add_tail(&region->list, pos);
+       list_splice(&stack, regions);
        return 0;
 }
 
@@ -1862,7 +1917,7 @@ EXPORT_SYMBOL_GPL(iommu_map);
 
 static size_t __iommu_unmap(struct iommu_domain *domain,
                            unsigned long iova, size_t size,
-                           bool sync)
+                           struct iommu_iotlb_gather *iotlb_gather)
 {
        const struct iommu_ops *ops = domain->ops;
        size_t unmapped_page, unmapped = 0;
@@ -1899,13 +1954,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
        while (unmapped < size) {
                size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
 
-               unmapped_page = ops->unmap(domain, iova, pgsize);
+               unmapped_page = ops->unmap(domain, iova, pgsize, iotlb_gather);
                if (!unmapped_page)
                        break;
 
-               if (sync && ops->iotlb_range_add)
-                       ops->iotlb_range_add(domain, iova, pgsize);
-
                pr_debug("unmapped: iova 0x%lx size 0x%zx\n",
                         iova, unmapped_page);
 
@@ -1913,9 +1965,6 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
                unmapped += unmapped_page;
        }
 
-       if (sync && ops->iotlb_sync)
-               ops->iotlb_sync(domain);
-
        trace_unmap(orig_iova, size, unmapped);
        return unmapped;
 }
@@ -1923,14 +1972,22 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 size_t iommu_unmap(struct iommu_domain *domain,
                   unsigned long iova, size_t size)
 {
-       return __iommu_unmap(domain, iova, size, true);
+       struct iommu_iotlb_gather iotlb_gather;
+       size_t ret;
+
+       iommu_iotlb_gather_init(&iotlb_gather);
+       ret = __iommu_unmap(domain, iova, size, &iotlb_gather);
+       iommu_tlb_sync(domain, &iotlb_gather);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 size_t iommu_unmap_fast(struct iommu_domain *domain,
-                       unsigned long iova, size_t size)
+                       unsigned long iova, size_t size,
+                       struct iommu_iotlb_gather *iotlb_gather)
 {
-       return __iommu_unmap(domain, iova, size, false);
+       return __iommu_unmap(domain, iova, size, iotlb_gather);
 }
 EXPORT_SYMBOL_GPL(iommu_unmap_fast);
 
@@ -2143,7 +2200,6 @@ request_default_domain_for_dev(struct device *dev, unsigned long type)
 
        mutex_lock(&group->mutex);
 
-       /* Check if the default domain is already direct mapped */
        ret = 0;
        if (group->default_domain && group->default_domain->type == type)
                goto out;
@@ -2153,7 +2209,6 @@ request_default_domain_for_dev(struct device *dev, unsigned long type)
        if (iommu_group_device_count(group) != 1)
                goto out;
 
-       /* Allocate a direct mapped domain */
        ret = -ENOMEM;
        domain = __iommu_domain_alloc(dev->bus, type);
        if (!domain)
@@ -2168,7 +2223,7 @@ request_default_domain_for_dev(struct device *dev, unsigned long type)
 
        iommu_group_create_direct_mappings(group, dev);
 
-       /* Make the direct mapped domain the default for this group */
+       /* Make the domain the default for this group */
        if (group->default_domain)
                iommu_domain_free(group->default_domain);
        group->default_domain = domain;
@@ -2196,6 +2251,28 @@ int iommu_request_dma_domain_for_dev(struct device *dev)
        return request_default_domain_for_dev(dev, IOMMU_DOMAIN_DMA);
 }
 
+void iommu_set_default_passthrough(bool cmd_line)
+{
+       if (cmd_line)
+               iommu_set_cmd_line_dma_api();
+
+       iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY;
+}
+
+void iommu_set_default_translated(bool cmd_line)
+{
+       if (cmd_line)
+               iommu_set_cmd_line_dma_api();
+
+       iommu_def_domain_type = IOMMU_DOMAIN_DMA;
+}
+
+bool iommu_default_passthrough(void)
+{
+       return iommu_def_domain_type == IOMMU_DOMAIN_IDENTITY;
+}
+EXPORT_SYMBOL_GPL(iommu_default_passthrough);
+
 const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
 {
        const struct iommu_ops *ops = NULL;
index 3e1a8a6..41c605b 100644 (file)
@@ -577,7 +577,9 @@ void queue_iova(struct iova_domain *iovad,
 
        spin_unlock_irqrestore(&fq->lock, flags);
 
-       if (atomic_cmpxchg(&iovad->fq_timer_on, 0, 1) == 0)
+       /* Avoid false sharing as much as possible. */
+       if (!atomic_read(&iovad->fq_timer_on) &&
+           !atomic_cmpxchg(&iovad->fq_timer_on, 0, 1))
                mod_timer(&iovad->fq_timer,
                          jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT));
 }
index ad0098c..9da8309 100644 (file)
@@ -49,6 +49,7 @@ struct ipmmu_features {
        bool setup_imbuscr;
        bool twobit_imttbcr_sl0;
        bool reserved_context;
+       bool cache_snoop;
 };
 
 struct ipmmu_vmsa_device {
@@ -115,45 +116,44 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
 #define IMTTBCR                                0x0008
 #define IMTTBCR_EAE                    (1 << 31)
 #define IMTTBCR_PMB                    (1 << 30)
-#define IMTTBCR_SH1_NON_SHAREABLE      (0 << 28)
-#define IMTTBCR_SH1_OUTER_SHAREABLE    (2 << 28)
-#define IMTTBCR_SH1_INNER_SHAREABLE    (3 << 28)
-#define IMTTBCR_SH1_MASK               (3 << 28)
-#define IMTTBCR_ORGN1_NC               (0 << 26)
-#define IMTTBCR_ORGN1_WB_WA            (1 << 26)
-#define IMTTBCR_ORGN1_WT               (2 << 26)
-#define IMTTBCR_ORGN1_WB               (3 << 26)
-#define IMTTBCR_ORGN1_MASK             (3 << 26)
-#define IMTTBCR_IRGN1_NC               (0 << 24)
-#define IMTTBCR_IRGN1_WB_WA            (1 << 24)
-#define IMTTBCR_IRGN1_WT               (2 << 24)
-#define IMTTBCR_IRGN1_WB               (3 << 24)
-#define IMTTBCR_IRGN1_MASK             (3 << 24)
+#define IMTTBCR_SH1_NON_SHAREABLE      (0 << 28)       /* R-Car Gen2 only */
+#define IMTTBCR_SH1_OUTER_SHAREABLE    (2 << 28)       /* R-Car Gen2 only */
+#define IMTTBCR_SH1_INNER_SHAREABLE    (3 << 28)       /* R-Car Gen2 only */
+#define IMTTBCR_SH1_MASK               (3 << 28)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN1_NC               (0 << 26)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN1_WB_WA            (1 << 26)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN1_WT               (2 << 26)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN1_WB               (3 << 26)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN1_MASK             (3 << 26)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN1_NC               (0 << 24)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN1_WB_WA            (1 << 24)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN1_WT               (2 << 24)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN1_WB               (3 << 24)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN1_MASK             (3 << 24)       /* R-Car Gen2 only */
 #define IMTTBCR_TSZ1_MASK              (7 << 16)
 #define IMTTBCR_TSZ1_SHIFT             16
-#define IMTTBCR_SH0_NON_SHAREABLE      (0 << 12)
-#define IMTTBCR_SH0_OUTER_SHAREABLE    (2 << 12)
-#define IMTTBCR_SH0_INNER_SHAREABLE    (3 << 12)
-#define IMTTBCR_SH0_MASK               (3 << 12)
-#define IMTTBCR_ORGN0_NC               (0 << 10)
-#define IMTTBCR_ORGN0_WB_WA            (1 << 10)
-#define IMTTBCR_ORGN0_WT               (2 << 10)
-#define IMTTBCR_ORGN0_WB               (3 << 10)
-#define IMTTBCR_ORGN0_MASK             (3 << 10)
-#define IMTTBCR_IRGN0_NC               (0 << 8)
-#define IMTTBCR_IRGN0_WB_WA            (1 << 8)
-#define IMTTBCR_IRGN0_WT               (2 << 8)
-#define IMTTBCR_IRGN0_WB               (3 << 8)
-#define IMTTBCR_IRGN0_MASK             (3 << 8)
+#define IMTTBCR_SH0_NON_SHAREABLE      (0 << 12)       /* R-Car Gen2 only */
+#define IMTTBCR_SH0_OUTER_SHAREABLE    (2 << 12)       /* R-Car Gen2 only */
+#define IMTTBCR_SH0_INNER_SHAREABLE    (3 << 12)       /* R-Car Gen2 only */
+#define IMTTBCR_SH0_MASK               (3 << 12)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN0_NC               (0 << 10)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN0_WB_WA            (1 << 10)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN0_WT               (2 << 10)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN0_WB               (3 << 10)       /* R-Car Gen2 only */
+#define IMTTBCR_ORGN0_MASK             (3 << 10)       /* R-Car Gen2 only */
+#define IMTTBCR_IRGN0_NC               (0 << 8)        /* R-Car Gen2 only */
+#define IMTTBCR_IRGN0_WB_WA            (1 << 8)        /* R-Car Gen2 only */
+#define IMTTBCR_IRGN0_WT               (2 << 8)        /* R-Car Gen2 only */
+#define IMTTBCR_IRGN0_WB               (3 << 8)        /* R-Car Gen2 only */
+#define IMTTBCR_IRGN0_MASK             (3 << 8)        /* R-Car Gen2 only */
+#define IMTTBCR_SL0_TWOBIT_LVL_3       (0 << 6)        /* R-Car Gen3 only */
+#define IMTTBCR_SL0_TWOBIT_LVL_2       (1 << 6)        /* R-Car Gen3 only */
+#define IMTTBCR_SL0_TWOBIT_LVL_1       (2 << 6)        /* R-Car Gen3 only */
 #define IMTTBCR_SL0_LVL_2              (0 << 4)
 #define IMTTBCR_SL0_LVL_1              (1 << 4)
 #define IMTTBCR_TSZ0_MASK              (7 << 0)
 #define IMTTBCR_TSZ0_SHIFT             O
 
-#define IMTTBCR_SL0_TWOBIT_LVL_3       (0 << 6)
-#define IMTTBCR_SL0_TWOBIT_LVL_2       (1 << 6)
-#define IMTTBCR_SL0_TWOBIT_LVL_1       (2 << 6)
-
 #define IMBUSCR                                0x000c
 #define IMBUSCR_DVM                    (1 << 2)
 #define IMBUSCR_BUSSEL_SYS             (0 << 0)
@@ -361,16 +361,16 @@ static void ipmmu_tlb_flush_all(void *cookie)
        ipmmu_tlb_invalidate(domain);
 }
 
-static void ipmmu_tlb_add_flush(unsigned long iova, size_t size,
-                               size_t granule, bool leaf, void *cookie)
+static void ipmmu_tlb_flush(unsigned long iova, size_t size,
+                               size_t granule, void *cookie)
 {
-       /* The hardware doesn't support selective TLB flush. */
+       ipmmu_tlb_flush_all(cookie);
 }
 
-static const struct iommu_gather_ops ipmmu_gather_ops = {
+static const struct iommu_flush_ops ipmmu_flush_ops = {
        .tlb_flush_all = ipmmu_tlb_flush_all,
-       .tlb_add_flush = ipmmu_tlb_add_flush,
-       .tlb_sync = ipmmu_tlb_flush_all,
+       .tlb_flush_walk = ipmmu_tlb_flush,
+       .tlb_flush_leaf = ipmmu_tlb_flush,
 };
 
 /* -----------------------------------------------------------------------------
@@ -422,17 +422,19 @@ static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain)
 
        /*
         * TTBCR
-        * We use long descriptors with inner-shareable WBWA tables and allocate
-        * the whole 32-bit VA space to TTBR0.
+        * We use long descriptors and allocate the whole 32-bit VA space to
+        * TTBR0.
         */
        if (domain->mmu->features->twobit_imttbcr_sl0)
                tmp = IMTTBCR_SL0_TWOBIT_LVL_1;
        else
                tmp = IMTTBCR_SL0_LVL_1;
 
-       ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE |
-                            IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
-                            IMTTBCR_IRGN0_WB_WA | tmp);
+       if (domain->mmu->features->cache_snoop)
+               tmp |= IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
+                      IMTTBCR_IRGN0_WB_WA;
+
+       ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | tmp);
 
        /* MAIR0 */
        ipmmu_ctx_write_root(domain, IMMAIR0,
@@ -480,7 +482,7 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
        domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K;
        domain->cfg.ias = 32;
        domain->cfg.oas = 40;
-       domain->cfg.tlb = &ipmmu_gather_ops;
+       domain->cfg.tlb = &ipmmu_flush_ops;
        domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
        domain->io_domain.geometry.force_aperture = true;
        /*
@@ -733,14 +735,14 @@ static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
 }
 
 static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova,
-                         size_t size)
+                         size_t size, struct iommu_iotlb_gather *gather)
 {
        struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
 
-       return domain->iop->unmap(domain->iop, iova, size);
+       return domain->iop->unmap(domain->iop, iova, size, gather);
 }
 
-static void ipmmu_iotlb_sync(struct iommu_domain *io_domain)
+static void ipmmu_flush_iotlb_all(struct iommu_domain *io_domain)
 {
        struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
 
@@ -748,6 +750,12 @@ static void ipmmu_iotlb_sync(struct iommu_domain *io_domain)
                ipmmu_tlb_flush_all(domain);
 }
 
+static void ipmmu_iotlb_sync(struct iommu_domain *io_domain,
+                            struct iommu_iotlb_gather *gather)
+{
+       ipmmu_flush_iotlb_all(io_domain);
+}
+
 static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
                                      dma_addr_t iova)
 {
@@ -957,7 +965,7 @@ static const struct iommu_ops ipmmu_ops = {
        .detach_dev = ipmmu_detach_device,
        .map = ipmmu_map,
        .unmap = ipmmu_unmap,
-       .flush_iotlb_all = ipmmu_iotlb_sync,
+       .flush_iotlb_all = ipmmu_flush_iotlb_all,
        .iotlb_sync = ipmmu_iotlb_sync,
        .iova_to_phys = ipmmu_iova_to_phys,
        .add_device = ipmmu_add_device,
@@ -988,6 +996,7 @@ static const struct ipmmu_features ipmmu_features_default = {
        .setup_imbuscr = true,
        .twobit_imttbcr_sl0 = false,
        .reserved_context = false,
+       .cache_snoop = true,
 };
 
 static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
@@ -998,6 +1007,7 @@ static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
        .setup_imbuscr = false,
        .twobit_imttbcr_sl0 = true,
        .reserved_context = true,
+       .cache_snoop = false,
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
index b25e2eb..be99d40 100644 (file)
@@ -168,20 +168,29 @@ fail:
        return;
 }
 
-static void __flush_iotlb_sync(void *cookie)
+static void __flush_iotlb_walk(unsigned long iova, size_t size,
+                              size_t granule, void *cookie)
 {
-       /*
-        * Nothing is needed here, the barrier to guarantee
-        * completion of the tlb sync operation is implicitly
-        * taken care when the iommu client does a writel before
-        * kick starting the other master.
-        */
+       __flush_iotlb_range(iova, size, granule, false, cookie);
+}
+
+static void __flush_iotlb_leaf(unsigned long iova, size_t size,
+                              size_t granule, void *cookie)
+{
+       __flush_iotlb_range(iova, size, granule, true, cookie);
 }
 
-static const struct iommu_gather_ops msm_iommu_gather_ops = {
+static void __flush_iotlb_page(struct iommu_iotlb_gather *gather,
+                              unsigned long iova, size_t granule, void *cookie)
+{
+       __flush_iotlb_range(iova, granule, granule, true, cookie);
+}
+
+static const struct iommu_flush_ops msm_iommu_flush_ops = {
        .tlb_flush_all = __flush_iotlb,
-       .tlb_add_flush = __flush_iotlb_range,
-       .tlb_sync = __flush_iotlb_sync,
+       .tlb_flush_walk = __flush_iotlb_walk,
+       .tlb_flush_leaf = __flush_iotlb_leaf,
+       .tlb_add_page = __flush_iotlb_page,
 };
 
 static int msm_iommu_alloc_ctx(unsigned long *map, int start, int end)
@@ -345,7 +354,7 @@ static int msm_iommu_domain_config(struct msm_priv *priv)
                .pgsize_bitmap = msm_iommu_ops.pgsize_bitmap,
                .ias = 32,
                .oas = 32,
-               .tlb = &msm_iommu_gather_ops,
+               .tlb = &msm_iommu_flush_ops,
                .iommu_dev = priv->dev,
        };
 
@@ -509,13 +518,13 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
-                             size_t len)
+                             size_t len, struct iommu_iotlb_gather *gather)
 {
        struct msm_priv *priv = to_msm_priv(domain);
        unsigned long flags;
 
        spin_lock_irqsave(&priv->pgtlock, flags);
-       len = priv->iop->unmap(priv->iop, iova, len);
+       len = priv->iop->unmap(priv->iop, iova, len, gather);
        spin_unlock_irqrestore(&priv->pgtlock, flags);
 
        return len;
@@ -691,6 +700,13 @@ static struct iommu_ops msm_iommu_ops = {
        .detach_dev = msm_iommu_detach_dev,
        .map = msm_iommu_map,
        .unmap = msm_iommu_unmap,
+       /*
+        * Nothing is needed here, the barrier to guarantee
+        * completion of the tlb sync operation is implicitly
+        * taken care when the iommu client does a writel before
+        * kick starting the other master.
+        */
+       .iotlb_sync = NULL,
        .iova_to_phys = msm_iommu_iova_to_phys,
        .add_device = msm_iommu_add_device,
        .remove_device = msm_iommu_remove_device,
@@ -750,7 +766,6 @@ static int msm_iommu_probe(struct platform_device *pdev)
 
        iommu->irq = platform_get_irq(pdev, 0);
        if (iommu->irq < 0) {
-               dev_err(iommu->dev, "could not get iommu irq\n");
                ret = -ENODEV;
                goto fail;
        }
index 82e4be4..67a483c 100644 (file)
@@ -28,6 +28,7 @@
 #include "mtk_iommu.h"
 
 #define REG_MMU_PT_BASE_ADDR                   0x000
+#define MMU_PT_ADDR_MASK                       GENMASK(31, 7)
 
 #define REG_MMU_INVALIDATE                     0x020
 #define F_ALL_INVLD                            0x2
 #define REG_MMU_DCM_DIS                                0x050
 
 #define REG_MMU_CTRL_REG                       0x110
+#define F_MMU_TF_PROT_TO_PROGRAM_ADDR          (2 << 4)
 #define F_MMU_PREFETCH_RT_REPLACE_MOD          BIT(4)
-#define F_MMU_TF_PROTECT_SEL_SHIFT(data) \
-       ((data)->m4u_plat == M4U_MT2712 ? 4 : 5)
-/* It's named by F_MMU_TF_PROT_SEL in mt2712. */
-#define F_MMU_TF_PROTECT_SEL(prot, data) \
-       (((prot) & 0x3) << F_MMU_TF_PROTECT_SEL_SHIFT(data))
+#define F_MMU_TF_PROT_TO_PROGRAM_ADDR_MT8173   (2 << 5)
 
 #define REG_MMU_IVRP_PADDR                     0x114
 
 #define F_INT_CLR_BIT                          BIT(12)
 
 #define REG_MMU_INT_MAIN_CONTROL               0x124
-#define F_INT_TRANSLATION_FAULT                        BIT(0)
-#define F_INT_MAIN_MULTI_HIT_FAULT             BIT(1)
-#define F_INT_INVALID_PA_FAULT                 BIT(2)
-#define F_INT_ENTRY_REPLACEMENT_FAULT          BIT(3)
-#define F_INT_TLB_MISS_FAULT                   BIT(4)
-#define F_INT_MISS_TRANSACTION_FIFO_FAULT      BIT(5)
-#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT   BIT(6)
+                                               /* mmu0 | mmu1 */
+#define F_INT_TRANSLATION_FAULT                        (BIT(0) | BIT(7))
+#define F_INT_MAIN_MULTI_HIT_FAULT             (BIT(1) | BIT(8))
+#define F_INT_INVALID_PA_FAULT                 (BIT(2) | BIT(9))
+#define F_INT_ENTRY_REPLACEMENT_FAULT          (BIT(3) | BIT(10))
+#define F_INT_TLB_MISS_FAULT                   (BIT(4) | BIT(11))
+#define F_INT_MISS_TRANSACTION_FIFO_FAULT      (BIT(5) | BIT(12))
+#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT   (BIT(6) | BIT(13))
 
 #define REG_MMU_CPE_DONE                       0x12C
 
 #define REG_MMU_FAULT_ST1                      0x134
+#define F_REG_MMU0_FAULT_MASK                  GENMASK(6, 0)
+#define F_REG_MMU1_FAULT_MASK                  GENMASK(13, 7)
 
-#define REG_MMU_FAULT_VA                       0x13c
+#define REG_MMU0_FAULT_VA                      0x13c
 #define F_MMU_FAULT_VA_WRITE_BIT               BIT(1)
 #define F_MMU_FAULT_VA_LAYER_BIT               BIT(0)
 
-#define REG_MMU_INVLD_PA                       0x140
-#define REG_MMU_INT_ID                         0x150
-#define F_MMU0_INT_ID_LARB_ID(a)               (((a) >> 7) & 0x7)
-#define F_MMU0_INT_ID_PORT_ID(a)               (((a) >> 2) & 0x1f)
+#define REG_MMU0_INVLD_PA                      0x140
+#define REG_MMU1_FAULT_VA                      0x144
+#define REG_MMU1_INVLD_PA                      0x148
+#define REG_MMU0_INT_ID                                0x150
+#define REG_MMU1_INT_ID                                0x154
+#define F_MMU_INT_ID_LARB_ID(a)                        (((a) >> 7) & 0x7)
+#define F_MMU_INT_ID_PORT_ID(a)                        (((a) >> 2) & 0x1f)
 
 #define MTK_PROTECT_PA_ALIGN                   128
 
@@ -107,6 +111,30 @@ struct mtk_iommu_domain {
 
 static const struct iommu_ops mtk_iommu_ops;
 
+/*
+ * In M4U 4GB mode, the physical address is remapped as below:
+ *
+ * CPU Physical address:
+ * ====================
+ *
+ * 0      1G       2G     3G       4G     5G
+ * |---A---|---B---|---C---|---D---|---E---|
+ * +--I/O--+------------Memory-------------+
+ *
+ * IOMMU output physical address:
+ *  =============================
+ *
+ *                                 4G      5G     6G      7G      8G
+ *                                 |---E---|---B---|---C---|---D---|
+ *                                 +------------Memory-------------+
+ *
+ * The Region 'A'(I/O) can NOT be mapped by M4U; For Region 'B'/'C'/'D', the
+ * bit32 of the CPU physical address always is needed to set, and for Region
+ * 'E', the CPU physical address keep as is.
+ * Additionally, The iommu consumers always use the CPU phyiscal address.
+ */
+#define MTK_IOMMU_4GB_MODE_REMAP_BASE   0x140000000UL
+
 static LIST_HEAD(m4ulist);     /* List all the M4U HWs */
 
 #define for_each_m4u(data)     list_for_each_entry(data, &m4ulist, list)
@@ -188,10 +216,32 @@ static void mtk_iommu_tlb_sync(void *cookie)
        }
 }
 
-static const struct iommu_gather_ops mtk_iommu_gather_ops = {
+static void mtk_iommu_tlb_flush_walk(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
+{
+       mtk_iommu_tlb_add_flush_nosync(iova, size, granule, false, cookie);
+       mtk_iommu_tlb_sync(cookie);
+}
+
+static void mtk_iommu_tlb_flush_leaf(unsigned long iova, size_t size,
+                                    size_t granule, void *cookie)
+{
+       mtk_iommu_tlb_add_flush_nosync(iova, size, granule, true, cookie);
+       mtk_iommu_tlb_sync(cookie);
+}
+
+static void mtk_iommu_tlb_flush_page_nosync(struct iommu_iotlb_gather *gather,
+                                           unsigned long iova, size_t granule,
+                                           void *cookie)
+{
+       mtk_iommu_tlb_add_flush_nosync(iova, granule, granule, true, cookie);
+}
+
+static const struct iommu_flush_ops mtk_iommu_flush_ops = {
        .tlb_flush_all = mtk_iommu_tlb_flush_all,
-       .tlb_add_flush = mtk_iommu_tlb_add_flush_nosync,
-       .tlb_sync = mtk_iommu_tlb_sync,
+       .tlb_flush_walk = mtk_iommu_tlb_flush_walk,
+       .tlb_flush_leaf = mtk_iommu_tlb_flush_leaf,
+       .tlb_add_page = mtk_iommu_tlb_flush_page_nosync,
 };
 
 static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
@@ -204,13 +254,21 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
 
        /* Read error info from registers */
        int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1);
-       fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+       if (int_state & F_REG_MMU0_FAULT_MASK) {
+               regval = readl_relaxed(data->base + REG_MMU0_INT_ID);
+               fault_iova = readl_relaxed(data->base + REG_MMU0_FAULT_VA);
+               fault_pa = readl_relaxed(data->base + REG_MMU0_INVLD_PA);
+       } else {
+               regval = readl_relaxed(data->base + REG_MMU1_INT_ID);
+               fault_iova = readl_relaxed(data->base + REG_MMU1_FAULT_VA);
+               fault_pa = readl_relaxed(data->base + REG_MMU1_INVLD_PA);
+       }
        layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT;
        write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
-       fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
-       regval = readl_relaxed(data->base + REG_MMU_INT_ID);
-       fault_larb = F_MMU0_INT_ID_LARB_ID(regval);
-       fault_port = F_MMU0_INT_ID_PORT_ID(regval);
+       fault_larb = F_MMU_INT_ID_LARB_ID(regval);
+       fault_port = F_MMU_INT_ID_PORT_ID(regval);
+
+       fault_larb = data->plat_data->larbid_remap[fault_larb];
 
        if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
                               write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
@@ -242,7 +300,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data,
        for (i = 0; i < fwspec->num_ids; ++i) {
                larbid = MTK_M4U_TO_LARB(fwspec->ids[i]);
                portid = MTK_M4U_TO_PORT(fwspec->ids[i]);
-               larb_mmu = &data->smi_imu.larb_imu[larbid];
+               larb_mmu = &data->larb_imu[larbid];
 
                dev_dbg(dev, "%s iommu port: %d\n",
                        enable ? "enable" : "disable", portid);
@@ -263,17 +321,15 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom)
        dom->cfg = (struct io_pgtable_cfg) {
                .quirks = IO_PGTABLE_QUIRK_ARM_NS |
                        IO_PGTABLE_QUIRK_NO_PERMS |
-                       IO_PGTABLE_QUIRK_TLBI_ON_MAP,
+                       IO_PGTABLE_QUIRK_TLBI_ON_MAP |
+                       IO_PGTABLE_QUIRK_ARM_MTK_EXT,
                .pgsize_bitmap = mtk_iommu_ops.pgsize_bitmap,
                .ias = 32,
-               .oas = 32,
-               .tlb = &mtk_iommu_gather_ops,
+               .oas = 34,
+               .tlb = &mtk_iommu_flush_ops,
                .iommu_dev = data->dev,
        };
 
-       if (data->enable_4GB)
-               dom->cfg.quirks |= IO_PGTABLE_QUIRK_ARM_MTK_4GB;
-
        dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
        if (!dom->iop) {
                dev_err(data->dev, "Failed to alloc io pgtable\n");
@@ -336,7 +392,7 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
        /* Update the pgtable base address register of the M4U HW */
        if (!data->m4u_dom) {
                data->m4u_dom = dom;
-               writel(dom->cfg.arm_v7s_cfg.ttbr[0],
+               writel(dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK,
                       data->base + REG_MMU_PT_BASE_ADDR);
        }
 
@@ -359,32 +415,43 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
                         phys_addr_t paddr, size_t size, int prot)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
+       struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
        unsigned long flags;
        int ret;
 
+       /* The "4GB mode" M4U physically can not use the lower remap of Dram. */
+       if (data->enable_4GB)
+               paddr |= BIT_ULL(32);
+
        spin_lock_irqsave(&dom->pgtlock, flags);
-       ret = dom->iop->map(dom->iop, iova, paddr & DMA_BIT_MASK(32),
-                           size, prot);
+       ret = dom->iop->map(dom->iop, iova, paddr, size, prot);
        spin_unlock_irqrestore(&dom->pgtlock, flags);
 
        return ret;
 }
 
 static size_t mtk_iommu_unmap(struct iommu_domain *domain,
-                             unsigned long iova, size_t size)
+                             unsigned long iova, size_t size,
+                             struct iommu_iotlb_gather *gather)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
        unsigned long flags;
        size_t unmapsz;
 
        spin_lock_irqsave(&dom->pgtlock, flags);
-       unmapsz = dom->iop->unmap(dom->iop, iova, size);
+       unmapsz = dom->iop->unmap(dom->iop, iova, size, gather);
        spin_unlock_irqrestore(&dom->pgtlock, flags);
 
        return unmapsz;
 }
 
-static void mtk_iommu_iotlb_sync(struct iommu_domain *domain)
+static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
+{
+       mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
+}
+
+static void mtk_iommu_iotlb_sync(struct iommu_domain *domain,
+                                struct iommu_iotlb_gather *gather)
 {
        mtk_iommu_tlb_sync(mtk_iommu_get_m4u_data());
 }
@@ -401,8 +468,8 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
        pa = dom->iop->iova_to_phys(dom->iop, iova);
        spin_unlock_irqrestore(&dom->pgtlock, flags);
 
-       if (data->enable_4GB)
-               pa |= BIT_ULL(32);
+       if (data->enable_4GB && pa >= MTK_IOMMU_4GB_MODE_REMAP_BASE)
+               pa &= ~BIT_ULL(32);
 
        return pa;
 }
@@ -490,7 +557,7 @@ static const struct iommu_ops mtk_iommu_ops = {
        .detach_dev     = mtk_iommu_detach_device,
        .map            = mtk_iommu_map,
        .unmap          = mtk_iommu_unmap,
-       .flush_iotlb_all = mtk_iommu_iotlb_sync,
+       .flush_iotlb_all = mtk_iommu_flush_iotlb_all,
        .iotlb_sync     = mtk_iommu_iotlb_sync,
        .iova_to_phys   = mtk_iommu_iova_to_phys,
        .add_device     = mtk_iommu_add_device,
@@ -511,9 +578,11 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
                return ret;
        }
 
-       regval = F_MMU_TF_PROTECT_SEL(2, data);
-       if (data->m4u_plat == M4U_MT8173)
-               regval |= F_MMU_PREFETCH_RT_REPLACE_MOD;
+       if (data->plat_data->m4u_plat == M4U_MT8173)
+               regval = F_MMU_PREFETCH_RT_REPLACE_MOD |
+                        F_MMU_TF_PROT_TO_PROGRAM_ADDR_MT8173;
+       else
+               regval = F_MMU_TF_PROT_TO_PROGRAM_ADDR;
        writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
 
        regval = F_L2_MULIT_HIT_EN |
@@ -533,14 +602,14 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
                F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
        writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
 
-       if (data->m4u_plat == M4U_MT8173)
+       if (data->plat_data->m4u_plat == M4U_MT8173)
                regval = (data->protect_base >> 1) | (data->enable_4GB << 31);
        else
                regval = lower_32_bits(data->protect_base) |
                         upper_32_bits(data->protect_base);
        writel_relaxed(regval, data->base + REG_MMU_IVRP_PADDR);
 
-       if (data->enable_4GB && data->m4u_plat != M4U_MT8173) {
+       if (data->enable_4GB && data->plat_data->has_vld_pa_rng) {
                /*
                 * If 4GB mode is enabled, the validate PA range is from
                 * 0x1_0000_0000 to 0x1_ffff_ffff. here record bit[32:30].
@@ -550,8 +619,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
        }
        writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
 
-       /* It's MISC control register whose default value is ok except mt8173.*/
-       if (data->m4u_plat == M4U_MT8173)
+       if (data->plat_data->reset_axi)
                writel_relaxed(0, data->base + REG_MMU_STANDARD_AXI_MODE);
 
        if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0,
@@ -584,7 +652,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
        data->dev = dev;
-       data->m4u_plat = (enum mtk_iommu_plat)of_device_get_match_data(dev);
+       data->plat_data = of_device_get_match_data(dev);
 
        /* Protect memory. HW will access here while translation fault.*/
        protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL);
@@ -594,6 +662,8 @@ static int mtk_iommu_probe(struct platform_device *pdev)
 
        /* Whether the current dram is over 4GB */
        data->enable_4GB = !!(max_pfn > (BIT_ULL(32) >> PAGE_SHIFT));
+       if (!data->plat_data->has_4gb_mode)
+               data->enable_4GB = false;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        data->base = devm_ioremap_resource(dev, res);
@@ -605,15 +675,16 @@ static int mtk_iommu_probe(struct platform_device *pdev)
        if (data->irq < 0)
                return data->irq;
 
-       data->bclk = devm_clk_get(dev, "bclk");
-       if (IS_ERR(data->bclk))
-               return PTR_ERR(data->bclk);
+       if (data->plat_data->has_bclk) {
+               data->bclk = devm_clk_get(dev, "bclk");
+               if (IS_ERR(data->bclk))
+                       return PTR_ERR(data->bclk);
+       }
 
        larb_nr = of_count_phandle_with_args(dev->of_node,
                                             "mediatek,larbs", NULL);
        if (larb_nr < 0)
                return larb_nr;
-       data->smi_imu.larb_nr = larb_nr;
 
        for (i = 0; i < larb_nr; i++) {
                struct device_node *larbnode;
@@ -638,7 +709,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
                        of_node_put(larbnode);
                        return -EPROBE_DEFER;
                }
-               data->smi_imu.larb_imu[id].dev = &plarbdev->dev;
+               data->larb_imu[id].dev = &plarbdev->dev;
 
                component_match_add_release(dev, &match, release_of,
                                            compare_of, larbnode);
@@ -699,6 +770,7 @@ static int __maybe_unused mtk_iommu_suspend(struct device *dev)
        reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
        reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
        reg->ivrp_paddr = readl_relaxed(base + REG_MMU_IVRP_PADDR);
+       reg->vld_pa_rng = readl_relaxed(base + REG_MMU_VLD_PA_RNG);
        clk_disable_unprepare(data->bclk);
        return 0;
 }
@@ -707,6 +779,7 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev)
 {
        struct mtk_iommu_data *data = dev_get_drvdata(dev);
        struct mtk_iommu_suspend_reg *reg = &data->reg;
+       struct mtk_iommu_domain *m4u_dom = data->m4u_dom;
        void __iomem *base = data->base;
        int ret;
 
@@ -722,8 +795,9 @@ static int __maybe_unused mtk_iommu_resume(struct device *dev)
        writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
        writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
        writel_relaxed(reg->ivrp_paddr, base + REG_MMU_IVRP_PADDR);
-       if (data->m4u_dom)
-               writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
+       writel_relaxed(reg->vld_pa_rng, base + REG_MMU_VLD_PA_RNG);
+       if (m4u_dom)
+               writel(m4u_dom->cfg.arm_v7s_cfg.ttbr[0] & MMU_PT_ADDR_MASK,
                       base + REG_MMU_PT_BASE_ADDR);
        return 0;
 }
@@ -732,9 +806,32 @@ static const struct dev_pm_ops mtk_iommu_pm_ops = {
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_iommu_suspend, mtk_iommu_resume)
 };
 
+static const struct mtk_iommu_plat_data mt2712_data = {
+       .m4u_plat     = M4U_MT2712,
+       .has_4gb_mode = true,
+       .has_bclk     = true,
+       .has_vld_pa_rng   = true,
+       .larbid_remap = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+};
+
+static const struct mtk_iommu_plat_data mt8173_data = {
+       .m4u_plat     = M4U_MT8173,
+       .has_4gb_mode = true,
+       .has_bclk     = true,
+       .reset_axi    = true,
+       .larbid_remap = {0, 1, 2, 3, 4, 5}, /* Linear mapping. */
+};
+
+static const struct mtk_iommu_plat_data mt8183_data = {
+       .m4u_plat     = M4U_MT8183,
+       .reset_axi    = true,
+       .larbid_remap = {0, 4, 5, 6, 7, 2, 3, 1},
+};
+
 static const struct of_device_id mtk_iommu_of_ids[] = {
-       { .compatible = "mediatek,mt2712-m4u", .data = (void *)M4U_MT2712},
-       { .compatible = "mediatek,mt8173-m4u", .data = (void *)M4U_MT8173},
+       { .compatible = "mediatek,mt2712-m4u", .data = &mt2712_data},
+       { .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data},
+       { .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data},
        {}
 };
 
index 5933732..fc0f16e 100644 (file)
@@ -24,12 +24,25 @@ struct mtk_iommu_suspend_reg {
        u32                             int_control0;
        u32                             int_main_control;
        u32                             ivrp_paddr;
+       u32                             vld_pa_rng;
 };
 
 enum mtk_iommu_plat {
        M4U_MT2701,
        M4U_MT2712,
        M4U_MT8173,
+       M4U_MT8183,
+};
+
+struct mtk_iommu_plat_data {
+       enum mtk_iommu_plat m4u_plat;
+       bool                has_4gb_mode;
+
+       /* HW will use the EMI clock if there isn't the "bclk". */
+       bool                has_bclk;
+       bool                has_vld_pa_rng;
+       bool                reset_axi;
+       unsigned char       larbid_remap[MTK_LARB_NR_MAX];
 };
 
 struct mtk_iommu_domain;
@@ -43,14 +56,14 @@ struct mtk_iommu_data {
        struct mtk_iommu_suspend_reg    reg;
        struct mtk_iommu_domain         *m4u_dom;
        struct iommu_group              *m4u_group;
-       struct mtk_smi_iommu            smi_imu;      /* SMI larb iommu info */
        bool                            enable_4GB;
        bool                            tlb_flush_active;
 
        struct iommu_device             iommu;
-       enum mtk_iommu_plat             m4u_plat;
+       const struct mtk_iommu_plat_data *plat_data;
 
        struct list_head                list;
+       struct mtk_smi_larb_iommu       larb_imu[MTK_LARB_NR_MAX];
 };
 
 static inline int compare_of(struct device *dev, void *data)
@@ -67,14 +80,14 @@ static inline int mtk_iommu_bind(struct device *dev)
 {
        struct mtk_iommu_data *data = dev_get_drvdata(dev);
 
-       return component_bind_all(dev, &data->smi_imu);
+       return component_bind_all(dev, &data->larb_imu);
 }
 
 static inline void mtk_iommu_unbind(struct device *dev)
 {
        struct mtk_iommu_data *data = dev_get_drvdata(dev);
 
-       component_unbind_all(dev, &data->smi_imu);
+       component_unbind_all(dev, &data->larb_imu);
 }
 
 #endif
index abeeac4..210b1c7 100644 (file)
@@ -206,7 +206,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data,
        for (i = 0; i < fwspec->num_ids; ++i) {
                larbid = mt2701_m4u_to_larb(fwspec->ids[i]);
                portid = mt2701_m4u_to_port(fwspec->ids[i]);
-               larb_mmu = &data->smi_imu.larb_imu[larbid];
+               larb_mmu = &data->larb_imu[larbid];
 
                dev_dbg(dev, "%s iommu port: %d\n",
                        enable ? "enable" : "disable", portid);
@@ -324,7 +324,8 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t mtk_iommu_unmap(struct iommu_domain *domain,
-                             unsigned long iova, size_t size)
+                             unsigned long iova, size_t size,
+                             struct iommu_iotlb_gather *gather)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
        unsigned long flags;
@@ -610,14 +611,12 @@ static int mtk_iommu_probe(struct platform_device *pdev)
                        }
                }
 
-               data->smi_imu.larb_imu[larb_nr].dev = &plarbdev->dev;
+               data->larb_imu[larb_nr].dev = &plarbdev->dev;
                component_match_add_release(dev, &match, release_of,
                                            compare_of, larb_spec.np);
                larb_nr++;
        }
 
-       data->smi_imu.larb_nr = larb_nr;
-
        platform_set_drvdata(pdev, data);
 
        ret = mtk_iommu_hw_init(data);
index dfb961d..09c6e1c 100644 (file)
 
 static const struct iommu_ops omap_iommu_ops;
 
+struct orphan_dev {
+       struct device *dev;
+       struct list_head node;
+};
+
+static LIST_HEAD(orphan_dev_list);
+
+static DEFINE_SPINLOCK(orphan_lock);
+
 #define to_iommu(dev)  ((struct omap_iommu *)dev_get_drvdata(dev))
 
 /* bitmap of the page sizes currently supported */
@@ -53,6 +62,8 @@ static const struct iommu_ops omap_iommu_ops;
 static struct platform_driver omap_iommu_driver;
 static struct kmem_cache *iopte_cachep;
 
+static int _omap_iommu_add_device(struct device *dev);
+
 /**
  * to_omap_domain - Get struct omap_iommu_domain from generic iommu_domain
  * @dom:       generic iommu domain handle
@@ -65,6 +76,9 @@ static struct omap_iommu_domain *to_omap_domain(struct iommu_domain *dom)
 /**
  * omap_iommu_save_ctx - Save registers for pm off-mode support
  * @dev:       client device
+ *
+ * This should be treated as an deprecated API. It is preserved only
+ * to maintain existing functionality for OMAP3 ISP driver.
  **/
 void omap_iommu_save_ctx(struct device *dev)
 {
@@ -92,6 +106,9 @@ EXPORT_SYMBOL_GPL(omap_iommu_save_ctx);
 /**
  * omap_iommu_restore_ctx - Restore registers for pm off-mode support
  * @dev:       client device
+ *
+ * This should be treated as an deprecated API. It is preserved only
+ * to maintain existing functionality for OMAP3 ISP driver.
  **/
 void omap_iommu_restore_ctx(struct device *dev)
 {
@@ -186,36 +203,18 @@ static void omap2_iommu_disable(struct omap_iommu *obj)
 
 static int iommu_enable(struct omap_iommu *obj)
 {
-       int err;
-       struct platform_device *pdev = to_platform_device(obj->dev);
-       struct iommu_platform_data *pdata = dev_get_platdata(&pdev->dev);
-
-       if (pdata && pdata->deassert_reset) {
-               err = pdata->deassert_reset(pdev, pdata->reset_name);
-               if (err) {
-                       dev_err(obj->dev, "deassert_reset failed: %d\n", err);
-                       return err;
-               }
-       }
-
-       pm_runtime_get_sync(obj->dev);
+       int ret;
 
-       err = omap2_iommu_enable(obj);
+       ret = pm_runtime_get_sync(obj->dev);
+       if (ret < 0)
+               pm_runtime_put_noidle(obj->dev);
 
-       return err;
+       return ret < 0 ? ret : 0;
 }
 
 static void iommu_disable(struct omap_iommu *obj)
 {
-       struct platform_device *pdev = to_platform_device(obj->dev);
-       struct iommu_platform_data *pdata = dev_get_platdata(&pdev->dev);
-
-       omap2_iommu_disable(obj);
-
        pm_runtime_put_sync(obj->dev);
-
-       if (pdata && pdata->assert_reset)
-               pdata->assert_reset(pdev, pdata->reset_name);
 }
 
 /*
@@ -901,15 +900,219 @@ static void omap_iommu_detach(struct omap_iommu *obj)
 
        dma_unmap_single(obj->dev, obj->pd_dma, IOPGD_TABLE_SIZE,
                         DMA_TO_DEVICE);
-       iommu_disable(obj);
        obj->pd_dma = 0;
        obj->iopgd = NULL;
+       iommu_disable(obj);
 
        spin_unlock(&obj->iommu_lock);
 
        dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
 }
 
+static void omap_iommu_save_tlb_entries(struct omap_iommu *obj)
+{
+       struct iotlb_lock lock;
+       struct cr_regs cr;
+       struct cr_regs *tmp;
+       int i;
+
+       /* check if there are any locked tlbs to save */
+       iotlb_lock_get(obj, &lock);
+       obj->num_cr_ctx = lock.base;
+       if (!obj->num_cr_ctx)
+               return;
+
+       tmp = obj->cr_ctx;
+       for_each_iotlb_cr(obj, obj->num_cr_ctx, i, cr)
+               * tmp++ = cr;
+}
+
+static void omap_iommu_restore_tlb_entries(struct omap_iommu *obj)
+{
+       struct iotlb_lock l;
+       struct cr_regs *tmp;
+       int i;
+
+       /* no locked tlbs to restore */
+       if (!obj->num_cr_ctx)
+               return;
+
+       l.base = 0;
+       tmp = obj->cr_ctx;
+       for (i = 0; i < obj->num_cr_ctx; i++, tmp++) {
+               l.vict = i;
+               iotlb_lock_set(obj, &l);
+               iotlb_load_cr(obj, tmp);
+       }
+       l.base = obj->num_cr_ctx;
+       l.vict = i;
+       iotlb_lock_set(obj, &l);
+}
+
+/**
+ * omap_iommu_domain_deactivate - deactivate attached iommu devices
+ * @domain: iommu domain attached to the target iommu device
+ *
+ * This API allows the client devices of IOMMU devices to suspend
+ * the IOMMUs they control at runtime, after they are idled and
+ * suspended all activity. System Suspend will leverage the PM
+ * driver late callbacks.
+ **/
+int omap_iommu_domain_deactivate(struct iommu_domain *domain)
+{
+       struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
+       struct omap_iommu_device *iommu;
+       struct omap_iommu *oiommu;
+       int i;
+
+       if (!omap_domain->dev)
+               return 0;
+
+       iommu = omap_domain->iommus;
+       iommu += (omap_domain->num_iommus - 1);
+       for (i = 0; i < omap_domain->num_iommus; i++, iommu--) {
+               oiommu = iommu->iommu_dev;
+               pm_runtime_put_sync(oiommu->dev);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_domain_deactivate);
+
+/**
+ * omap_iommu_domain_activate - activate attached iommu devices
+ * @domain: iommu domain attached to the target iommu device
+ *
+ * This API allows the client devices of IOMMU devices to resume the
+ * IOMMUs they control at runtime, before they can resume operations.
+ * System Resume will leverage the PM driver late callbacks.
+ **/
+int omap_iommu_domain_activate(struct iommu_domain *domain)
+{
+       struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
+       struct omap_iommu_device *iommu;
+       struct omap_iommu *oiommu;
+       int i;
+
+       if (!omap_domain->dev)
+               return 0;
+
+       iommu = omap_domain->iommus;
+       for (i = 0; i < omap_domain->num_iommus; i++, iommu++) {
+               oiommu = iommu->iommu_dev;
+               pm_runtime_get_sync(oiommu->dev);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_iommu_domain_activate);
+
+/**
+ * omap_iommu_runtime_suspend - disable an iommu device
+ * @dev:       iommu device
+ *
+ * This function performs all that is necessary to disable an
+ * IOMMU device, either during final detachment from a client
+ * device, or during system/runtime suspend of the device. This
+ * includes programming all the appropriate IOMMU registers, and
+ * managing the associated omap_hwmod's state and the device's
+ * reset line. This function also saves the context of any
+ * locked TLBs if suspending.
+ **/
+static __maybe_unused int omap_iommu_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct iommu_platform_data *pdata = dev_get_platdata(dev);
+       struct omap_iommu *obj = to_iommu(dev);
+       int ret;
+
+       /* save the TLBs only during suspend, and not for power down */
+       if (obj->domain && obj->iopgd)
+               omap_iommu_save_tlb_entries(obj);
+
+       omap2_iommu_disable(obj);
+
+       if (pdata && pdata->device_idle)
+               pdata->device_idle(pdev);
+
+       if (pdata && pdata->assert_reset)
+               pdata->assert_reset(pdev, pdata->reset_name);
+
+       if (pdata && pdata->set_pwrdm_constraint) {
+               ret = pdata->set_pwrdm_constraint(pdev, false, &obj->pwrst);
+               if (ret) {
+                       dev_warn(obj->dev, "pwrdm_constraint failed to be reset, status = %d\n",
+                                ret);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * omap_iommu_runtime_resume - enable an iommu device
+ * @dev:       iommu device
+ *
+ * This function performs all that is necessary to enable an
+ * IOMMU device, either during initial attachment to a client
+ * device, or during system/runtime resume of the device. This
+ * includes programming all the appropriate IOMMU registers, and
+ * managing the associated omap_hwmod's state and the device's
+ * reset line. The function also restores any locked TLBs if
+ * resuming after a suspend.
+ **/
+static __maybe_unused int omap_iommu_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct iommu_platform_data *pdata = dev_get_platdata(dev);
+       struct omap_iommu *obj = to_iommu(dev);
+       int ret = 0;
+
+       if (pdata && pdata->set_pwrdm_constraint) {
+               ret = pdata->set_pwrdm_constraint(pdev, true, &obj->pwrst);
+               if (ret) {
+                       dev_warn(obj->dev, "pwrdm_constraint failed to be set, status = %d\n",
+                                ret);
+               }
+       }
+
+       if (pdata && pdata->deassert_reset) {
+               ret = pdata->deassert_reset(pdev, pdata->reset_name);
+               if (ret) {
+                       dev_err(dev, "deassert_reset failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (pdata && pdata->device_enable)
+               pdata->device_enable(pdev);
+
+       /* restore the TLBs only during resume, and not for power up */
+       if (obj->domain)
+               omap_iommu_restore_tlb_entries(obj);
+
+       ret = omap2_iommu_enable(obj);
+
+       return ret;
+}
+
+/**
+ * omap_iommu_suspend_prepare - prepare() dev_pm_ops implementation
+ * @dev:       iommu device
+ *
+ * This function performs the necessary checks to determine if the IOMMU
+ * device needs suspending or not. The function checks if the runtime_pm
+ * status of the device is suspended, and returns 1 in that case. This
+ * results in the PM core to skip invoking any of the Sleep PM callbacks
+ * (suspend, suspend_late, resume, resume_early etc).
+ */
+static int omap_iommu_prepare(struct device *dev)
+{
+       if (pm_runtime_status_suspended(dev))
+               return 1;
+       return 0;
+}
+
 static bool omap_iommu_can_register(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -974,6 +1177,7 @@ static int omap_iommu_probe(struct platform_device *pdev)
        struct omap_iommu *obj;
        struct resource *res;
        struct device_node *of = pdev->dev.of_node;
+       struct orphan_dev *orphan_dev, *tmp;
 
        if (!of) {
                pr_err("%s: only DT-based devices are supported\n", __func__);
@@ -984,6 +1188,15 @@ static int omap_iommu_probe(struct platform_device *pdev)
        if (!obj)
                return -ENOMEM;
 
+       /*
+        * self-manage the ordering dependencies between omap_device_enable/idle
+        * and omap_device_assert/deassert_hardreset API
+        */
+       if (pdev->dev.pm_domain) {
+               dev_dbg(&pdev->dev, "device pm_domain is being reset\n");
+               pdev->dev.pm_domain = NULL;
+       }
+
        obj->name = dev_name(&pdev->dev);
        obj->nr_tlb_entries = 32;
        err = of_property_read_u32(of, "ti,#tlb-entries", &obj->nr_tlb_entries);
@@ -996,6 +1209,11 @@ static int omap_iommu_probe(struct platform_device *pdev)
 
        obj->dev = &pdev->dev;
        obj->ctx = (void *)obj + sizeof(*obj);
+       obj->cr_ctx = devm_kzalloc(&pdev->dev,
+                                  sizeof(*obj->cr_ctx) * obj->nr_tlb_entries,
+                                  GFP_KERNEL);
+       if (!obj->cr_ctx)
+               return -ENOMEM;
 
        spin_lock_init(&obj->iommu_lock);
        spin_lock_init(&obj->page_table_lock);
@@ -1036,13 +1254,20 @@ static int omap_iommu_probe(struct platform_device *pdev)
                        goto out_sysfs;
        }
 
-       pm_runtime_irq_safe(obj->dev);
        pm_runtime_enable(obj->dev);
 
        omap_iommu_debugfs_add(obj);
 
        dev_info(&pdev->dev, "%s registered\n", obj->name);
 
+       list_for_each_entry_safe(orphan_dev, tmp, &orphan_dev_list, node) {
+               err = _omap_iommu_add_device(orphan_dev->dev);
+               if (!err) {
+                       list_del(&orphan_dev->node);
+                       kfree(orphan_dev);
+               }
+       }
+
        return 0;
 
 out_sysfs:
@@ -1072,6 +1297,14 @@ static int omap_iommu_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct dev_pm_ops omap_iommu_pm_ops = {
+       .prepare = omap_iommu_prepare,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                    pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(omap_iommu_runtime_suspend,
+                          omap_iommu_runtime_resume, NULL)
+};
+
 static const struct of_device_id omap_iommu_of_match[] = {
        { .compatible = "ti,omap2-iommu" },
        { .compatible = "ti,omap4-iommu" },
@@ -1085,6 +1318,7 @@ static struct platform_driver omap_iommu_driver = {
        .remove = omap_iommu_remove,
        .driver = {
                .name   = "omap-iommu",
+               .pm     = &omap_iommu_pm_ops,
                .of_match_table = of_match_ptr(omap_iommu_of_match),
        },
 };
@@ -1149,7 +1383,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
 }
 
 static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
-                              size_t size)
+                              size_t size, struct iommu_iotlb_gather *gather)
 {
        struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
        struct device *dev = omap_domain->dev;
@@ -1423,7 +1657,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
        return ret;
 }
 
-static int omap_iommu_add_device(struct device *dev)
+static int _omap_iommu_add_device(struct device *dev)
 {
        struct omap_iommu_arch_data *arch_data, *tmp;
        struct omap_iommu *oiommu;
@@ -1432,6 +1666,8 @@ static int omap_iommu_add_device(struct device *dev)
        struct platform_device *pdev;
        int num_iommus, i;
        int ret;
+       struct orphan_dev *orphan_dev;
+       unsigned long flags;
 
        /*
         * Allocate the archdata iommu structure for DT-based devices.
@@ -1463,10 +1699,26 @@ static int omap_iommu_add_device(struct device *dev)
                }
 
                pdev = of_find_device_by_node(np);
-               if (WARN_ON(!pdev)) {
+               if (!pdev) {
                        of_node_put(np);
                        kfree(arch_data);
-                       return -EINVAL;
+                       spin_lock_irqsave(&orphan_lock, flags);
+                       list_for_each_entry(orphan_dev, &orphan_dev_list,
+                                           node) {
+                               if (orphan_dev->dev == dev)
+                                       break;
+                       }
+                       spin_unlock_irqrestore(&orphan_lock, flags);
+
+                       if (orphan_dev && orphan_dev->dev == dev)
+                               return -EPROBE_DEFER;
+
+                       orphan_dev = kzalloc(sizeof(*orphan_dev), GFP_KERNEL);
+                       orphan_dev->dev = dev;
+                       spin_lock_irqsave(&orphan_lock, flags);
+                       list_add(&orphan_dev->node, &orphan_dev_list);
+                       spin_unlock_irqrestore(&orphan_lock, flags);
+                       return -EPROBE_DEFER;
                }
 
                oiommu = platform_get_drvdata(pdev);
@@ -1477,6 +1729,7 @@ static int omap_iommu_add_device(struct device *dev)
                }
 
                tmp->iommu_dev = oiommu;
+               tmp->dev = &pdev->dev;
 
                of_node_put(np);
        }
@@ -1511,6 +1764,17 @@ static int omap_iommu_add_device(struct device *dev)
        return 0;
 }
 
+static int omap_iommu_add_device(struct device *dev)
+{
+       int ret;
+
+       ret = _omap_iommu_add_device(dev);
+       if (ret == -EPROBE_DEFER)
+               return 0;
+
+       return ret;
+}
+
 static void omap_iommu_remove_device(struct device *dev)
 {
        struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
@@ -1554,7 +1818,7 @@ static const struct iommu_ops omap_iommu_ops = {
 static int __init omap_iommu_init(void)
 {
        struct kmem_cache *p;
-       const unsigned long flags = SLAB_HWCACHE_ALIGN;
+       const slab_flags_t flags = SLAB_HWCACHE_ALIGN;
        size_t align = 1 << 10; /* L2 pagetable alignement */
        struct device_node *np;
        int ret;
index 09968a0..18ee713 100644 (file)
@@ -73,16 +73,22 @@ struct omap_iommu {
 
        void *ctx; /* iommu context: registres saved area */
 
+       struct cr_regs *cr_ctx;
+       u32 num_cr_ctx;
+
        int has_bus_err_back;
        u32 id;
 
        struct iommu_device iommu;
        struct iommu_group *group;
+
+       u8 pwrst;
 };
 
 /**
  * struct omap_iommu_arch_data - omap iommu private data
- * @iommu_dev: handle of the iommu device
+ * @iommu_dev: handle of the OMAP iommu device
+ * @dev: handle of the iommu device
  *
  * This is an omap iommu private data object, which binds an iommu user
  * to its iommu device. This object should be placed at the iommu user's
@@ -91,6 +97,7 @@ struct omap_iommu {
  */
 struct omap_iommu_arch_data {
        struct omap_iommu *iommu_dev;
+       struct device *dev;
 };
 
 struct cr_regs {
index 34d0b97..c31e7bc 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/dma-iommu.h>
@@ -32,7 +33,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
-#include "arm-smmu-regs.h"
+#include "arm-smmu.h"
 
 #define SMMU_INTR_SEL_NS     0x2000
 
@@ -155,7 +156,7 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size,
                struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
                size_t s = size;
 
-               iova &= ~12UL;
+               iova = (iova >> 12) << 12;
                iova |= ctx->asid;
                do {
                        iommu_writel(ctx, reg, iova);
@@ -164,10 +165,32 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size,
        }
 }
 
-static const struct iommu_gather_ops qcom_gather_ops = {
+static void qcom_iommu_tlb_flush_walk(unsigned long iova, size_t size,
+                                     size_t granule, void *cookie)
+{
+       qcom_iommu_tlb_inv_range_nosync(iova, size, granule, false, cookie);
+       qcom_iommu_tlb_sync(cookie);
+}
+
+static void qcom_iommu_tlb_flush_leaf(unsigned long iova, size_t size,
+                                     size_t granule, void *cookie)
+{
+       qcom_iommu_tlb_inv_range_nosync(iova, size, granule, true, cookie);
+       qcom_iommu_tlb_sync(cookie);
+}
+
+static void qcom_iommu_tlb_add_page(struct iommu_iotlb_gather *gather,
+                                   unsigned long iova, size_t granule,
+                                   void *cookie)
+{
+       qcom_iommu_tlb_inv_range_nosync(iova, granule, granule, true, cookie);
+}
+
+static const struct iommu_flush_ops qcom_flush_ops = {
        .tlb_flush_all  = qcom_iommu_tlb_inv_context,
-       .tlb_add_flush  = qcom_iommu_tlb_inv_range_nosync,
-       .tlb_sync       = qcom_iommu_tlb_sync,
+       .tlb_flush_walk = qcom_iommu_tlb_flush_walk,
+       .tlb_flush_leaf = qcom_iommu_tlb_flush_leaf,
+       .tlb_add_page   = qcom_iommu_tlb_add_page,
 };
 
 static irqreturn_t qcom_iommu_fault(int irq, void *dev)
@@ -215,7 +238,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
                .pgsize_bitmap  = qcom_iommu_ops.pgsize_bitmap,
                .ias            = 32,
                .oas            = 40,
-               .tlb            = &qcom_gather_ops,
+               .tlb            = &qcom_flush_ops,
                .iommu_dev      = qcom_iommu->dev,
        };
 
@@ -247,16 +270,16 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
                /* TTBRs */
                iommu_writeq(ctx, ARM_SMMU_CB_TTBR0,
                                pgtbl_cfg.arm_lpae_s1_cfg.ttbr[0] |
-                               ((u64)ctx->asid << TTBRn_ASID_SHIFT));
+                               FIELD_PREP(TTBRn_ASID, ctx->asid));
                iommu_writeq(ctx, ARM_SMMU_CB_TTBR1,
                                pgtbl_cfg.arm_lpae_s1_cfg.ttbr[1] |
-                               ((u64)ctx->asid << TTBRn_ASID_SHIFT));
+                               FIELD_PREP(TTBRn_ASID, ctx->asid));
 
-               /* TTBCR */
-               iommu_writel(ctx, ARM_SMMU_CB_TTBCR2,
+               /* TCR */
+               iommu_writel(ctx, ARM_SMMU_CB_TCR2,
                                (pgtbl_cfg.arm_lpae_s1_cfg.tcr >> 32) |
-                               TTBCR2_SEP_UPSTREAM);
-               iommu_writel(ctx, ARM_SMMU_CB_TTBCR,
+                               FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM));
+               iommu_writel(ctx, ARM_SMMU_CB_TCR,
                                pgtbl_cfg.arm_lpae_s1_cfg.tcr);
 
                /* MAIRs (stage-1 only) */
@@ -417,7 +440,7 @@ static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
-                              size_t size)
+                              size_t size, struct iommu_iotlb_gather *gather)
 {
        size_t ret;
        unsigned long flags;
@@ -434,14 +457,14 @@ static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
         */
        pm_runtime_get_sync(qcom_domain->iommu->dev);
        spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags);
-       ret = ops->unmap(ops, iova, size);
+       ret = ops->unmap(ops, iova, size, gather);
        spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags);
        pm_runtime_put_sync(qcom_domain->iommu->dev);
 
        return ret;
 }
 
-static void qcom_iommu_iotlb_sync(struct iommu_domain *domain)
+static void qcom_iommu_flush_iotlb_all(struct iommu_domain *domain)
 {
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
        struct io_pgtable *pgtable = container_of(qcom_domain->pgtbl_ops,
@@ -454,6 +477,12 @@ static void qcom_iommu_iotlb_sync(struct iommu_domain *domain)
        pm_runtime_put_sync(qcom_domain->iommu->dev);
 }
 
+static void qcom_iommu_iotlb_sync(struct iommu_domain *domain,
+                                 struct iommu_iotlb_gather *gather)
+{
+       qcom_iommu_flush_iotlb_all(domain);
+}
+
 static phys_addr_t qcom_iommu_iova_to_phys(struct iommu_domain *domain,
                                           dma_addr_t iova)
 {
@@ -581,7 +610,7 @@ static const struct iommu_ops qcom_iommu_ops = {
        .detach_dev     = qcom_iommu_detach_dev,
        .map            = qcom_iommu_map,
        .unmap          = qcom_iommu_unmap,
-       .flush_iotlb_all = qcom_iommu_iotlb_sync,
+       .flush_iotlb_all = qcom_iommu_flush_iotlb_all,
        .iotlb_sync     = qcom_iommu_iotlb_sync,
        .iova_to_phys   = qcom_iommu_iova_to_phys,
        .add_device     = qcom_iommu_add_device,
@@ -696,10 +725,8 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev)
                return PTR_ERR(ctx->base);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "failed to get irq\n");
+       if (irq < 0)
                return -ENODEV;
-       }
 
        /* clear IRQs before registering fault handler, just in case the
         * boot-loader left us a surprise:
@@ -775,7 +802,7 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
        struct qcom_iommu_dev *qcom_iommu;
        struct device *dev = &pdev->dev;
        struct resource *res;
-       int ret, sz, max_asid = 0;
+       int ret, max_asid = 0;
 
        /* find the max asid (which is 1:1 to ctx bank idx), so we know how
         * many child ctx devices we have:
@@ -783,9 +810,8 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
        for_each_child_of_node(dev->of_node, child)
                max_asid = max(max_asid, get_asid(child));
 
-       sz = sizeof(*qcom_iommu) + (max_asid * sizeof(qcom_iommu->ctxs[0]));
-
-       qcom_iommu = devm_kzalloc(dev, sz, GFP_KERNEL);
+       qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid),
+                                 GFP_KERNEL);
        if (!qcom_iommu)
                return -ENOMEM;
        qcom_iommu->num_ctxs = max_asid;
index dc26d74..26290f3 100644 (file)
@@ -794,7 +794,7 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
 }
 
 static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
-                            size_t size)
+                            size_t size, struct iommu_iotlb_gather *gather)
 {
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
        unsigned long flags;
index 22d4db3..3b0b18e 100644 (file)
@@ -314,7 +314,8 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain,
 }
 
 static size_t s390_iommu_unmap(struct iommu_domain *domain,
-                              unsigned long iova, size_t size)
+                              unsigned long iova, size_t size,
+                              struct iommu_iotlb_gather *gather)
 {
        struct s390_domain *s390_domain = to_s390_domain(domain);
        int flags = ZPCI_PTE_INVALID;
index 6d40bc1..3924f7c 100644 (file)
@@ -207,7 +207,7 @@ static inline int __gart_iommu_unmap(struct gart_device *gart,
 }
 
 static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
-                              size_t bytes)
+                              size_t bytes, struct iommu_iotlb_gather *gather)
 {
        struct gart_device *gart = gart_handle;
        int err;
@@ -273,11 +273,17 @@ static int gart_iommu_of_xlate(struct device *dev,
        return 0;
 }
 
-static void gart_iommu_sync(struct iommu_domain *domain)
+static void gart_iommu_sync_map(struct iommu_domain *domain)
 {
        FLUSH_GART_REGS(gart_handle);
 }
 
+static void gart_iommu_sync(struct iommu_domain *domain,
+                           struct iommu_iotlb_gather *gather)
+{
+       gart_iommu_sync_map(domain);
+}
+
 static const struct iommu_ops gart_iommu_ops = {
        .capable        = gart_iommu_capable,
        .domain_alloc   = gart_iommu_domain_alloc,
@@ -292,7 +298,7 @@ static const struct iommu_ops gart_iommu_ops = {
        .iova_to_phys   = gart_iommu_iova_to_phys,
        .pgsize_bitmap  = GART_IOMMU_PGSIZES,
        .of_xlate       = gart_iommu_of_xlate,
-       .iotlb_sync_map = gart_iommu_sync,
+       .iotlb_sync_map = gart_iommu_sync_map,
        .iotlb_sync     = gart_iommu_sync,
 };
 
index c4a652b..7293fc3 100644 (file)
@@ -680,7 +680,7 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
-                              size_t size)
+                              size_t size, struct iommu_iotlb_gather *gather)
 {
        struct tegra_smmu_as *as = to_smmu_as(domain);
        dma_addr_t pte_dma;
index 80a740d..3ea9d76 100644 (file)
@@ -751,7 +751,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova,
 }
 
 static size_t viommu_unmap(struct iommu_domain *domain, unsigned long iova,
-                          size_t size)
+                          size_t size, struct iommu_iotlb_gather *gather)
 {
        int ret = 0;
        size_t unmapped;
@@ -797,7 +797,8 @@ static phys_addr_t viommu_iova_to_phys(struct iommu_domain *domain,
        return paddr;
 }
 
-static void viommu_iotlb_sync(struct iommu_domain *domain)
+static void viommu_iotlb_sync(struct iommu_domain *domain,
+                             struct iommu_iotlb_gather *gather)
 {
        struct viommu_domain *vdomain = to_viommu_domain(domain);
 
index cf75596..c72c036 100644 (file)
@@ -244,6 +244,7 @@ static int __init plic_init(struct device_node *node,
                struct plic_handler *handler;
                irq_hw_number_t hwirq;
                int cpu, hartid;
+               u32 threshold = 0;
 
                if (of_irq_parse_one(node, i, &parent)) {
                        pr_err("failed to parse parent for context %d.\n", i);
@@ -266,10 +267,16 @@ static int __init plic_init(struct device_node *node,
                        continue;
                }
 
+               /*
+                * When running in M-mode we need to ignore the S-mode handler.
+                * Here we assume it always comes later, but that might be a
+                * little fragile.
+                */
                handler = per_cpu_ptr(&plic_handlers, cpu);
                if (handler->present) {
                        pr_warn("handler already present for context %d.\n", i);
-                       continue;
+                       threshold = 0xffffffff;
+                       goto done;
                }
 
                handler->present = true;
@@ -279,8 +286,9 @@ static int __init plic_init(struct device_node *node,
                handler->enable_base =
                        plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
 
+done:
                /* priority must be > threshold to trigger an interrupt */
-               writel(0, handler->hart_base + CONTEXT_THRESHOLD);
+               writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
                for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
                        plic_toggle(handler, hwirq, 0);
                nr_handlers++;
index 3c3ad42..c92b405 100644 (file)
@@ -688,6 +688,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        if (!cdev->ap.applid)
                return -ENODEV;
 
+       if (count < CAPIMSG_BASELEN)
+               return -EINVAL;
+
        skb = alloc_skb(count, GFP_USER);
        if (!skb)
                return -ENOMEM;
@@ -698,7 +701,8 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        }
        mlen = CAPIMSG_LEN(skb->data);
        if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
-               if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
+               if (count < CAPI_DATA_B3_REQ_LEN ||
+                   (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
                        kfree_skb(skb);
                        return -EINVAL;
                }
@@ -711,6 +715,10 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
 
        if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
+               if (count < CAPI_DISCONNECT_B3_RESP_LEN) {
+                       kfree_skb(skb);
+                       return -EINVAL;
+               }
                mutex_lock(&cdev->lock);
                capincci_free(cdev, CAPIMSG_NCCI(skb->data));
                mutex_unlock(&cdev->lock);
index b6b5acc..2a48ea3 100644 (file)
@@ -1599,7 +1599,9 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
        unsigned long freed;
 
        c = container_of(shrink, struct dm_bufio_client, shrinker);
-       if (!dm_bufio_trylock(c))
+       if (sc->gfp_mask & __GFP_FS)
+               dm_bufio_lock(c);
+       else if (!dm_bufio_trylock(c))
                return SHRINK_STOP;
 
        freed  = __scan(c, sc->nr_to_scan, sc->gfp_mask);
index 845f376..8288887 100644 (file)
@@ -25,6 +25,7 @@ struct dust_device {
        unsigned long long badblock_count;
        spinlock_t dust_lock;
        unsigned int blksz;
+       int sect_per_block_shift;
        unsigned int sect_per_block;
        sector_t start;
        bool fail_read_on_bb:1;
@@ -79,7 +80,7 @@ static int dust_remove_block(struct dust_device *dd, unsigned long long block)
        unsigned long flags;
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+       bblock = dust_rb_search(&dd->badblocklist, block);
 
        if (bblock == NULL) {
                if (!dd->quiet_mode) {
@@ -113,7 +114,7 @@ static int dust_add_block(struct dust_device *dd, unsigned long long block)
        }
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock->bb = block * dd->sect_per_block;
+       bblock->bb = block;
        if (!dust_rb_insert(&dd->badblocklist, bblock)) {
                if (!dd->quiet_mode) {
                        DMERR("%s: block %llu already in badblocklist",
@@ -138,7 +139,7 @@ static int dust_query_block(struct dust_device *dd, unsigned long long block)
        unsigned long flags;
 
        spin_lock_irqsave(&dd->dust_lock, flags);
-       bblock = dust_rb_search(&dd->badblocklist, block * dd->sect_per_block);
+       bblock = dust_rb_search(&dd->badblocklist, block);
        if (bblock != NULL)
                DMINFO("%s: block %llu found in badblocklist", __func__, block);
        else
@@ -165,6 +166,7 @@ static int dust_map_read(struct dust_device *dd, sector_t thisblock,
        int ret = DM_MAPIO_REMAPPED;
 
        if (fail_read_on_bb) {
+               thisblock >>= dd->sect_per_block_shift;
                spin_lock_irqsave(&dd->dust_lock, flags);
                ret = __dust_map_read(dd, thisblock);
                spin_unlock_irqrestore(&dd->dust_lock, flags);
@@ -195,6 +197,7 @@ static int dust_map_write(struct dust_device *dd, sector_t thisblock,
        unsigned long flags;
 
        if (fail_read_on_bb) {
+               thisblock >>= dd->sect_per_block_shift;
                spin_lock_irqsave(&dd->dust_lock, flags);
                __dust_map_write(dd, thisblock);
                spin_unlock_irqrestore(&dd->dust_lock, flags);
@@ -331,6 +334,8 @@ static int dust_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        dd->blksz = blksz;
        dd->start = tmp;
 
+       dd->sect_per_block_shift = __ffs(sect_per_block);
+
        /*
         * Whether to fail a read on a "bad" block.
         * Defaults to false; enabled later by message.
index b1b0de4..9118ab8 100644 (file)
@@ -1943,7 +1943,22 @@ offload_to_thread:
                        queue_work(ic->wait_wq, &dio->work);
                        return;
                }
+               if (journal_read_pos != NOT_FOUND)
+                       dio->range.n_sectors = ic->sectors_per_block;
                wait_and_add_new_range(ic, &dio->range);
+               /*
+                * wait_and_add_new_range drops the spinlock, so the journal
+                * may have been changed arbitrarily. We need to recheck.
+                * To simplify the code, we restrict I/O size to just one block.
+                */
+               if (journal_read_pos != NOT_FOUND) {
+                       sector_t next_sector;
+                       unsigned new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+                       if (unlikely(new_pos != journal_read_pos)) {
+                               remove_range_unlocked(ic, &dio->range);
+                               goto retry;
+                       }
+               }
        }
        spin_unlock_irq(&ic->endio_wait.lock);
 
index df2011d..1bbe4a3 100644 (file)
@@ -566,8 +566,10 @@ static int run_io_job(struct kcopyd_job *job)
         * no point in continuing.
         */
        if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
-           job->master_job->write_err)
+           job->master_job->write_err) {
+               job->write_err = job->master_job->write_err;
                return -EIO;
+       }
 
        io_job_start(job->kc->throttle);
 
@@ -619,6 +621,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
                        else
                                job->read_err = 1;
                        push(&kc->complete_jobs, job);
+                       wake(kc);
                        break;
                }
 
index 8a60a4a..1f933dd 100644 (file)
@@ -3194,7 +3194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                          */
                        r = rs_prepare_reshape(rs);
                        if (r)
-                               return r;
+                               goto bad;
 
                        /* Reshaping ain't recovery, so disable recovery */
                        rs_setup_recovery(rs, MaxSector);
index 7b6c3ee..8820931 100644 (file)
@@ -1342,7 +1342,7 @@ void dm_table_event(struct dm_table *t)
 }
 EXPORT_SYMBOL(dm_table_event);
 
-sector_t dm_table_get_size(struct dm_table *t)
+inline sector_t dm_table_get_size(struct dm_table *t)
 {
        return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
 }
@@ -1367,6 +1367,9 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
        unsigned int l, n = 0, k = 0;
        sector_t *node;
 
+       if (unlikely(sector >= dm_table_get_size(t)))
+               return &t->targets[t->num_targets];
+
        for (l = 0; l < t->depth; l++) {
                n = get_child(n, k);
                node = get_node(t, l, n);
index 8545dce..595a731 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -34,7 +35,7 @@
  *    (1) Super block (1 block)
  *    (2) Chunk mapping table (nr_map_blocks)
  *    (3) Bitmap blocks (nr_bitmap_blocks)
- * All metadata blocks are stored in conventional zones, starting from the
+ * All metadata blocks are stored in conventional zones, starting from
  * the first conventional zone found on disk.
  */
 struct dmz_super {
@@ -233,7 +234,7 @@ void dmz_unlock_map(struct dmz_metadata *zmd)
  * Lock/unlock metadata access. This is a "read" lock on a semaphore
  * that prevents metadata flush from running while metadata are being
  * modified. The actual metadata write mutual exclusion is achieved with
- * the map lock and zone styate management (active and reclaim state are
+ * the map lock and zone state management (active and reclaim state are
  * mutually exclusive).
  */
 void dmz_lock_metadata(struct dmz_metadata *zmd)
@@ -402,15 +403,18 @@ static struct dmz_mblock *dmz_get_mblock_slow(struct dmz_metadata *zmd,
        sector_t block = zmd->sb[zmd->mblk_primary].block + mblk_no;
        struct bio *bio;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return ERR_PTR(-EIO);
+
        /* Get a new block and a BIO to read it */
        mblk = dmz_alloc_mblock(zmd, mblk_no);
        if (!mblk)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio) {
                dmz_free_mblock(zmd, mblk);
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
        spin_lock(&zmd->mblk_lock);
@@ -541,8 +545,8 @@ static struct dmz_mblock *dmz_get_mblock(struct dmz_metadata *zmd,
        if (!mblk) {
                /* Cache miss: read the block from disk */
                mblk = dmz_get_mblock_slow(zmd, mblk_no);
-               if (!mblk)
-                       return ERR_PTR(-ENOMEM);
+               if (IS_ERR(mblk))
+                       return mblk;
        }
 
        /* Wait for on-going read I/O and check for error */
@@ -570,16 +574,19 @@ static void dmz_dirty_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk)
 /*
  * Issue a metadata block write BIO.
  */
-static void dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
-                            unsigned int set)
+static int dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
+                           unsigned int set)
 {
        sector_t block = zmd->sb[set].block + mblk->no;
        struct bio *bio;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return -EIO;
+
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio) {
                set_bit(DMZ_META_ERROR, &mblk->state);
-               return;
+               return -ENOMEM;
        }
 
        set_bit(DMZ_META_WRITING, &mblk->state);
@@ -591,6 +598,8 @@ static void dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
        bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_META | REQ_PRIO);
        bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0);
        submit_bio(bio);
+
+       return 0;
 }
 
 /*
@@ -602,6 +611,9 @@ static int dmz_rdwr_block(struct dmz_metadata *zmd, int op, sector_t block,
        struct bio *bio;
        int ret;
 
+       if (dmz_bdev_is_dying(zmd->dev))
+               return -EIO;
+
        bio = bio_alloc(GFP_NOIO, 1);
        if (!bio)
                return -ENOMEM;
@@ -659,22 +671,29 @@ static int dmz_write_dirty_mblocks(struct dmz_metadata *zmd,
 {
        struct dmz_mblock *mblk;
        struct blk_plug plug;
-       int ret = 0;
+       int ret = 0, nr_mblks_submitted = 0;
 
        /* Issue writes */
        blk_start_plug(&plug);
-       list_for_each_entry(mblk, write_list, link)
-               dmz_write_mblock(zmd, mblk, set);
+       list_for_each_entry(mblk, write_list, link) {
+               ret = dmz_write_mblock(zmd, mblk, set);
+               if (ret)
+                       break;
+               nr_mblks_submitted++;
+       }
        blk_finish_plug(&plug);
 
        /* Wait for completion */
        list_for_each_entry(mblk, write_list, link) {
+               if (!nr_mblks_submitted)
+                       break;
                wait_on_bit_io(&mblk->state, DMZ_META_WRITING,
                               TASK_UNINTERRUPTIBLE);
                if (test_bit(DMZ_META_ERROR, &mblk->state)) {
                        clear_bit(DMZ_META_ERROR, &mblk->state);
                        ret = -EIO;
                }
+               nr_mblks_submitted--;
        }
 
        /* Flush drive cache (this will also sync data) */
@@ -736,6 +755,11 @@ int dmz_flush_metadata(struct dmz_metadata *zmd)
         */
        dmz_lock_flush(zmd);
 
+       if (dmz_bdev_is_dying(zmd->dev)) {
+               ret = -EIO;
+               goto out;
+       }
+
        /* Get dirty blocks */
        spin_lock(&zmd->mblk_lock);
        list_splice_init(&zmd->mblk_dirty_list, &write_list);
@@ -1542,7 +1566,7 @@ static struct dm_zone *dmz_get_rnd_zone_for_reclaim(struct dmz_metadata *zmd)
        struct dm_zone *zone;
 
        if (list_empty(&zmd->map_rnd_list))
-               return NULL;
+               return ERR_PTR(-EBUSY);
 
        list_for_each_entry(zone, &zmd->map_rnd_list, link) {
                if (dmz_is_buf(zone))
@@ -1553,7 +1577,7 @@ static struct dm_zone *dmz_get_rnd_zone_for_reclaim(struct dmz_metadata *zmd)
                        return dzone;
        }
 
-       return NULL;
+       return ERR_PTR(-EBUSY);
 }
 
 /*
@@ -1564,7 +1588,7 @@ static struct dm_zone *dmz_get_seq_zone_for_reclaim(struct dmz_metadata *zmd)
        struct dm_zone *zone;
 
        if (list_empty(&zmd->map_seq_list))
-               return NULL;
+               return ERR_PTR(-EBUSY);
 
        list_for_each_entry(zone, &zmd->map_seq_list, link) {
                if (!zone->bzone)
@@ -1573,7 +1597,7 @@ static struct dm_zone *dmz_get_seq_zone_for_reclaim(struct dmz_metadata *zmd)
                        return zone;
        }
 
-       return NULL;
+       return ERR_PTR(-EBUSY);
 }
 
 /*
@@ -1628,9 +1652,13 @@ again:
                if (op != REQ_OP_WRITE)
                        goto out;
 
-               /* Alloate a random zone */
+               /* Allocate a random zone */
                dzone = dmz_alloc_zone(zmd, DMZ_ALLOC_RND);
                if (!dzone) {
+                       if (dmz_bdev_is_dying(zmd->dev)) {
+                               dzone = ERR_PTR(-EIO);
+                               goto out;
+                       }
                        dmz_wait_for_free_zones(zmd);
                        goto again;
                }
@@ -1725,9 +1753,13 @@ again:
        if (bzone)
                goto out;
 
-       /* Alloate a random zone */
+       /* Allocate a random zone */
        bzone = dmz_alloc_zone(zmd, DMZ_ALLOC_RND);
        if (!bzone) {
+               if (dmz_bdev_is_dying(zmd->dev)) {
+                       bzone = ERR_PTR(-EIO);
+                       goto out;
+               }
                dmz_wait_for_free_zones(zmd);
                goto again;
        }
index edf4b95..d240d7c 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -37,7 +38,7 @@ enum {
 /*
  * Number of seconds of target BIO inactivity to consider the target idle.
  */
-#define DMZ_IDLE_PERIOD                (10UL * HZ)
+#define DMZ_IDLE_PERIOD                        (10UL * HZ)
 
 /*
  * Percentage of unmapped (free) random zones below which reclaim starts
@@ -134,6 +135,9 @@ static int dmz_reclaim_copy(struct dmz_reclaim *zrc,
                set_bit(DM_KCOPYD_WRITE_SEQ, &flags);
 
        while (block < end_block) {
+               if (dev->flags & DMZ_BDEV_DYING)
+                       return -EIO;
+
                /* Get a valid region from the source zone */
                ret = dmz_first_valid_block(zmd, src_zone, &block);
                if (ret <= 0)
@@ -215,7 +219,7 @@ static int dmz_reclaim_buf(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -259,7 +263,7 @@ static int dmz_reclaim_seq_data(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -312,7 +316,7 @@ static int dmz_reclaim_rnd_data(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 
        dmz_unlock_flush(zmd);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -334,7 +338,7 @@ static void dmz_reclaim_empty(struct dmz_reclaim *zrc, struct dm_zone *dzone)
 /*
  * Find a candidate zone for reclaim and process it.
  */
-static void dmz_reclaim(struct dmz_reclaim *zrc)
+static int dmz_do_reclaim(struct dmz_reclaim *zrc)
 {
        struct dmz_metadata *zmd = zrc->metadata;
        struct dm_zone *dzone;
@@ -344,8 +348,8 @@ static void dmz_reclaim(struct dmz_reclaim *zrc)
 
        /* Get a data zone */
        dzone = dmz_get_zone_for_reclaim(zmd);
-       if (!dzone)
-               return;
+       if (IS_ERR(dzone))
+               return PTR_ERR(dzone);
 
        start = jiffies;
 
@@ -391,13 +395,20 @@ static void dmz_reclaim(struct dmz_reclaim *zrc)
 out:
        if (ret) {
                dmz_unlock_zone_reclaim(dzone);
-               return;
+               return ret;
        }
 
-       (void) dmz_flush_metadata(zrc->metadata);
+       ret = dmz_flush_metadata(zrc->metadata);
+       if (ret) {
+               dmz_dev_debug(zrc->dev,
+                             "Metadata flush for zone %u failed, err %d\n",
+                             dmz_id(zmd, rzone), ret);
+               return ret;
+       }
 
        dmz_dev_debug(zrc->dev, "Reclaimed zone %u in %u ms",
                      dmz_id(zmd, rzone), jiffies_to_msecs(jiffies - start));
+       return 0;
 }
 
 /*
@@ -427,7 +438,7 @@ static bool dmz_should_reclaim(struct dmz_reclaim *zrc)
                return false;
 
        /*
-        * If the percentage of unmappped random zones is low,
+        * If the percentage of unmapped random zones is low,
         * reclaim even if the target is busy.
         */
        return p_unmap_rnd <= DMZ_RECLAIM_LOW_UNMAP_RND;
@@ -442,6 +453,10 @@ static void dmz_reclaim_work(struct work_struct *work)
        struct dmz_metadata *zmd = zrc->metadata;
        unsigned int nr_rnd, nr_unmap_rnd;
        unsigned int p_unmap_rnd;
+       int ret;
+
+       if (dmz_bdev_is_dying(zrc->dev))
+               return;
 
        if (!dmz_should_reclaim(zrc)) {
                mod_delayed_work(zrc->wq, &zrc->work, DMZ_IDLE_PERIOD);
@@ -471,7 +486,17 @@ static void dmz_reclaim_work(struct work_struct *work)
                      (dmz_target_idle(zrc) ? "Idle" : "Busy"),
                      p_unmap_rnd, nr_unmap_rnd, nr_rnd);
 
-       dmz_reclaim(zrc);
+       ret = dmz_do_reclaim(zrc);
+       if (ret) {
+               dmz_dev_debug(zrc->dev, "Reclaim error %d\n", ret);
+               if (ret == -EIO)
+                       /*
+                        * LLD might be performing some error handling sequence
+                        * at the underlying device. To not interfere, do not
+                        * attempt to schedule the next reclaim run immediately.
+                        */
+                       return;
+       }
 
        dmz_schedule_reclaim(zrc);
 }
index 51d029b..31478fe 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -133,6 +134,8 @@ static int dmz_submit_bio(struct dmz_target *dmz, struct dm_zone *zone,
 
        refcount_inc(&bioctx->ref);
        generic_make_request(clone);
+       if (clone->bi_status == BLK_STS_IOERR)
+               return -EIO;
 
        if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
                zone->wp_block += nr_blocks;
@@ -277,8 +280,8 @@ static int dmz_handle_buffered_write(struct dmz_target *dmz,
 
        /* Get the buffer zone. One will be allocated if needed */
        bzone = dmz_get_chunk_buffer(zmd, zone);
-       if (!bzone)
-               return -ENOSPC;
+       if (IS_ERR(bzone))
+               return PTR_ERR(bzone);
 
        if (dmz_is_readonly(bzone))
                return -EROFS;
@@ -389,6 +392,11 @@ static void dmz_handle_bio(struct dmz_target *dmz, struct dm_chunk_work *cw,
 
        dmz_lock_metadata(zmd);
 
+       if (dmz->dev->flags & DMZ_BDEV_DYING) {
+               ret = -EIO;
+               goto out;
+       }
+
        /*
         * Get the data zone mapping the chunk. There may be no
         * mapping for read and discard. If a mapping is obtained,
@@ -493,6 +501,8 @@ static void dmz_flush_work(struct work_struct *work)
 
        /* Flush dirty metadata blocks */
        ret = dmz_flush_metadata(dmz->metadata);
+       if (ret)
+               dmz_dev_debug(dmz->dev, "Metadata flush failed, rc=%d\n", ret);
 
        /* Process queued flush requests */
        while (1) {
@@ -513,22 +523,24 @@ static void dmz_flush_work(struct work_struct *work)
  * Get a chunk work and start it to process a new BIO.
  * If the BIO chunk has no work yet, create one.
  */
-static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
+static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
 {
        unsigned int chunk = dmz_bio_chunk(dmz->dev, bio);
        struct dm_chunk_work *cw;
+       int ret = 0;
 
        mutex_lock(&dmz->chunk_lock);
 
        /* Get the BIO chunk work. If one is not active yet, create one */
        cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
        if (!cw) {
-               int ret;
 
                /* Create a new chunk work */
                cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
-               if (!cw)
+               if (unlikely(!cw)) {
+                       ret = -ENOMEM;
                        goto out;
+               }
 
                INIT_WORK(&cw->work, dmz_chunk_work);
                refcount_set(&cw->refcount, 0);
@@ -539,7 +551,6 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
                ret = radix_tree_insert(&dmz->chunk_rxtree, chunk, cw);
                if (unlikely(ret)) {
                        kfree(cw);
-                       cw = NULL;
                        goto out;
                }
        }
@@ -547,10 +558,38 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
        bio_list_add(&cw->bio_list, bio);
        dmz_get_chunk_work(cw);
 
+       dmz_reclaim_bio_acc(dmz->reclaim);
        if (queue_work(dmz->chunk_wq, &cw->work))
                dmz_get_chunk_work(cw);
 out:
        mutex_unlock(&dmz->chunk_lock);
+       return ret;
+}
+
+/*
+ * Check the backing device availability. If it's on the way out,
+ * start failing I/O. Reclaim and metadata components also call this
+ * function to cleanly abort operation in the event of such failure.
+ */
+bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev)
+{
+       struct gendisk *disk;
+
+       if (!(dmz_dev->flags & DMZ_BDEV_DYING)) {
+               disk = dmz_dev->bdev->bd_disk;
+               if (blk_queue_dying(bdev_get_queue(dmz_dev->bdev))) {
+                       dmz_dev_warn(dmz_dev, "Backing device queue dying");
+                       dmz_dev->flags |= DMZ_BDEV_DYING;
+               } else if (disk->fops->check_events) {
+                       if (disk->fops->check_events(disk, 0) &
+                                       DISK_EVENT_MEDIA_CHANGE) {
+                               dmz_dev_warn(dmz_dev, "Backing device offline");
+                               dmz_dev->flags |= DMZ_BDEV_DYING;
+                       }
+               }
+       }
+
+       return dmz_dev->flags & DMZ_BDEV_DYING;
 }
 
 /*
@@ -564,6 +603,10 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
        sector_t sector = bio->bi_iter.bi_sector;
        unsigned int nr_sectors = bio_sectors(bio);
        sector_t chunk_sector;
+       int ret;
+
+       if (dmz_bdev_is_dying(dmz->dev))
+               return DM_MAPIO_KILL;
 
        dmz_dev_debug(dev, "BIO op %d sector %llu + %u => chunk %llu, block %llu, %u blocks",
                      bio_op(bio), (unsigned long long)sector, nr_sectors,
@@ -601,8 +644,14 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
                dm_accept_partial_bio(bio, dev->zone_nr_sectors - chunk_sector);
 
        /* Now ready to handle this BIO */
-       dmz_reclaim_bio_acc(dmz->reclaim);
-       dmz_queue_chunk_work(dmz, bio);
+       ret = dmz_queue_chunk_work(dmz, bio);
+       if (ret) {
+               dmz_dev_debug(dmz->dev,
+                             "BIO op %d, can't process chunk %llu, err %i\n",
+                             bio_op(bio), (u64)dmz_bio_chunk(dmz->dev, bio),
+                             ret);
+               return DM_MAPIO_REQUEUE;
+       }
 
        return DM_MAPIO_SUBMITTED;
 }
@@ -855,6 +904,9 @@ static int dmz_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
 {
        struct dmz_target *dmz = ti->private;
 
+       if (dmz_bdev_is_dying(dmz->dev))
+               return -ENODEV;
+
        *bdev = dmz->dev->bdev;
 
        return 0;
index ed8de49..d8e70b0 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2017 Western Digital Corporation or its affiliates.
  *
@@ -56,6 +57,8 @@ struct dmz_dev {
 
        unsigned int            nr_zones;
 
+       unsigned int            flags;
+
        sector_t                zone_nr_sectors;
        unsigned int            zone_nr_sectors_shift;
 
@@ -67,6 +70,9 @@ struct dmz_dev {
                                 (dev)->zone_nr_sectors_shift)
 #define dmz_chunk_block(dev, b)        ((b) & ((dev)->zone_nr_blocks - 1))
 
+/* Device flags. */
+#define DMZ_BDEV_DYING         (1 << 0)
+
 /*
  * Zone descriptor.
  */
@@ -245,4 +251,9 @@ void dmz_resume_reclaim(struct dmz_reclaim *zrc);
 void dmz_reclaim_bio_acc(struct dmz_reclaim *zrc);
 void dmz_schedule_reclaim(struct dmz_reclaim *zrc);
 
+/*
+ * Functions defined in dm-zoned-target.c
+ */
+bool dmz_bdev_is_dying(struct dmz_dev *dmz_dev);
+
 #endif /* DM_ZONED_H */
index 58b3197..8aae062 100644 (file)
@@ -628,39 +628,40 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
 
        new_parent = shadow_current(s);
 
+       pn = dm_block_data(new_parent);
+       size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
+               sizeof(__le64) : s->info->value_type.size;
+
+       /* create & init the left block */
        r = new_block(s->info, &left);
        if (r < 0)
                return r;
 
+       ln = dm_block_data(left);
+       nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
+
+       ln->header.flags = pn->header.flags;
+       ln->header.nr_entries = cpu_to_le32(nr_left);
+       ln->header.max_entries = pn->header.max_entries;
+       ln->header.value_size = pn->header.value_size;
+       memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
+       memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+
+       /* create & init the right block */
        r = new_block(s->info, &right);
        if (r < 0) {
                unlock_block(s->info, left);
                return r;
        }
 
-       pn = dm_block_data(new_parent);
-       ln = dm_block_data(left);
        rn = dm_block_data(right);
-
-       nr_left = le32_to_cpu(pn->header.nr_entries) / 2;
        nr_right = le32_to_cpu(pn->header.nr_entries) - nr_left;
 
-       ln->header.flags = pn->header.flags;
-       ln->header.nr_entries = cpu_to_le32(nr_left);
-       ln->header.max_entries = pn->header.max_entries;
-       ln->header.value_size = pn->header.value_size;
-
        rn->header.flags = pn->header.flags;
        rn->header.nr_entries = cpu_to_le32(nr_right);
        rn->header.max_entries = pn->header.max_entries;
        rn->header.value_size = pn->header.value_size;
-
-       memcpy(ln->keys, pn->keys, nr_left * sizeof(pn->keys[0]));
        memcpy(rn->keys, pn->keys + nr_left, nr_right * sizeof(pn->keys[0]));
-
-       size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
-               sizeof(__le64) : s->info->value_type.size;
-       memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
        memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
               nr_right * size);
 
index aec4492..2532858 100644 (file)
@@ -249,7 +249,7 @@ static int out(struct sm_metadata *smm)
        }
 
        if (smm->recursion_count == 1)
-               apply_bops(smm);
+               r = apply_bops(smm);
 
        smm->recursion_count--;
 
index 29e3f5d..11ec048 100644 (file)
@@ -253,8 +253,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
         */
 
        pixsize = vout->bpp * vout->vrfb_bpp;
-       dst_icg = ((MAX_PIXELS_PER_LINE * pixsize) -
-                 (vout->pix.width * vout->bpp)) + 1;
+       dst_icg = MAX_PIXELS_PER_LINE * pixsize - vout->pix.width * vout->bpp;
 
        xt->src_start = vout->buf_phy_addr[vb->i];
        xt->dst_start = vout->vrfb_context[vb->i].paddr[0];
index 42ab43a..439d7d8 100644 (file)
 #define SMI_LARB_NONSEC_CON(id)        (0x380 + ((id) * 4))
 #define F_MMU_EN               BIT(0)
 
+/* SMI COMMON */
+#define SMI_BUS_SEL                    0x220
+#define SMI_BUS_LARB_SHIFT(larbid)     ((larbid) << 1)
+/* All are MMU0 defaultly. Only specialize mmu1 here. */
+#define F_MMU1_LARB(larbid)            (0x1 << SMI_BUS_LARB_SHIFT(larbid))
+
+enum mtk_smi_gen {
+       MTK_SMI_GEN1,
+       MTK_SMI_GEN2
+};
+
+struct mtk_smi_common_plat {
+       enum mtk_smi_gen gen;
+       bool             has_gals;
+       u32              bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
+};
+
 struct mtk_smi_larb_gen {
-       bool need_larbid;
        int port_in_larb[MTK_LARB_NR_MAX + 1];
        void (*config_port)(struct device *);
+       unsigned int                    larb_direct_to_common_mask;
+       bool                            has_gals;
 };
 
 struct mtk_smi {
        struct device                   *dev;
        struct clk                      *clk_apb, *clk_smi;
+       struct clk                      *clk_gals0, *clk_gals1;
        struct clk                      *clk_async; /*only needed by mt2701*/
-       void __iomem                    *smi_ao_base;
+       union {
+               void __iomem            *smi_ao_base; /* only for gen1 */
+               void __iomem            *base;        /* only for gen2 */
+       };
+       const struct mtk_smi_common_plat *plat;
 };
 
 struct mtk_smi_larb { /* larb: local arbiter */
@@ -63,82 +86,56 @@ struct mtk_smi_larb { /* larb: local arbiter */
        u32                             *mmu;
 };
 
-enum mtk_smi_gen {
-       MTK_SMI_GEN1,
-       MTK_SMI_GEN2
-};
-
-static int mtk_smi_enable(const struct mtk_smi *smi)
+static int mtk_smi_clk_enable(const struct mtk_smi *smi)
 {
        int ret;
 
-       ret = pm_runtime_get_sync(smi->dev);
-       if (ret < 0)
-               return ret;
-
        ret = clk_prepare_enable(smi->clk_apb);
        if (ret)
-               goto err_put_pm;
+               return ret;
 
        ret = clk_prepare_enable(smi->clk_smi);
        if (ret)
                goto err_disable_apb;
 
+       ret = clk_prepare_enable(smi->clk_gals0);
+       if (ret)
+               goto err_disable_smi;
+
+       ret = clk_prepare_enable(smi->clk_gals1);
+       if (ret)
+               goto err_disable_gals0;
+
        return 0;
 
+err_disable_gals0:
+       clk_disable_unprepare(smi->clk_gals0);
+err_disable_smi:
+       clk_disable_unprepare(smi->clk_smi);
 err_disable_apb:
        clk_disable_unprepare(smi->clk_apb);
-err_put_pm:
-       pm_runtime_put_sync(smi->dev);
        return ret;
 }
 
-static void mtk_smi_disable(const struct mtk_smi *smi)
+static void mtk_smi_clk_disable(const struct mtk_smi *smi)
 {
+       clk_disable_unprepare(smi->clk_gals1);
+       clk_disable_unprepare(smi->clk_gals0);
        clk_disable_unprepare(smi->clk_smi);
        clk_disable_unprepare(smi->clk_apb);
-       pm_runtime_put_sync(smi->dev);
 }
 
 int mtk_smi_larb_get(struct device *larbdev)
 {
-       struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
-       const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
-       struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
-       int ret;
-
-       /* Enable the smi-common's power and clocks */
-       ret = mtk_smi_enable(common);
-       if (ret)
-               return ret;
+       int ret = pm_runtime_get_sync(larbdev);
 
-       /* Enable the larb's power and clocks */
-       ret = mtk_smi_enable(&larb->smi);
-       if (ret) {
-               mtk_smi_disable(common);
-               return ret;
-       }
-
-       /* Configure the iommu info for this larb */
-       larb_gen->config_port(larbdev);
-
-       return 0;
+       return (ret < 0) ? ret : 0;
 }
 EXPORT_SYMBOL_GPL(mtk_smi_larb_get);
 
 void mtk_smi_larb_put(struct device *larbdev)
 {
-       struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
-       struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
-
-       /*
-        * Don't de-configure the iommu info for this larb since there may be
-        * several modules in this larb.
-        * The iommu info will be reset after power off.
-        */
-
-       mtk_smi_disable(&larb->smi);
-       mtk_smi_disable(common);
+       pm_runtime_put_sync(larbdev);
 }
 EXPORT_SYMBOL_GPL(mtk_smi_larb_put);
 
@@ -146,39 +143,26 @@ static int
 mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
 {
        struct mtk_smi_larb *larb = dev_get_drvdata(dev);
-       struct mtk_smi_iommu *smi_iommu = data;
+       struct mtk_smi_larb_iommu *larb_mmu = data;
        unsigned int         i;
 
-       if (larb->larb_gen->need_larbid) {
-               larb->mmu = &smi_iommu->larb_imu[larb->larbid].mmu;
-               return 0;
-       }
-
-       /*
-        * If there is no larbid property, Loop to find the corresponding
-        * iommu information.
-        */
-       for (i = 0; i < smi_iommu->larb_nr; i++) {
-               if (dev == smi_iommu->larb_imu[i].dev) {
-                       /* The 'mmu' may be updated in iommu-attach/detach. */
-                       larb->mmu = &smi_iommu->larb_imu[i].mmu;
+       for (i = 0; i < MTK_LARB_NR_MAX; i++) {
+               if (dev == larb_mmu[i].dev) {
+                       larb->larbid = i;
+                       larb->mmu = &larb_mmu[i].mmu;
                        return 0;
                }
        }
        return -ENODEV;
 }
 
-static void mtk_smi_larb_config_port_mt2712(struct device *dev)
+static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
 {
        struct mtk_smi_larb *larb = dev_get_drvdata(dev);
        u32 reg;
        int i;
 
-       /*
-        * larb 8/9 is the bdpsys larb, the iommu_en is enabled defaultly.
-        * Don't need to set it again.
-        */
-       if (larb->larbid == 8 || larb->larbid == 9)
+       if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
                return;
 
        for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
@@ -243,7 +227,6 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
 };
 
 static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
-       .need_larbid = true,
        .port_in_larb = {
                LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
                LARB2_PORT_OFFSET, LARB3_PORT_OFFSET
@@ -252,8 +235,15 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
 };
 
 static const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = {
-       .need_larbid = true,
-       .config_port = mtk_smi_larb_config_port_mt2712,
+       .config_port                = mtk_smi_larb_config_port_gen2_general,
+       .larb_direct_to_common_mask = BIT(8) | BIT(9),      /* bdpsys */
+};
+
+static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
+       .has_gals                   = true,
+       .config_port                = mtk_smi_larb_config_port_gen2_general,
+       .larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7),
+                                     /* IPU0 | IPU1 | CCU */
 };
 
 static const struct of_device_id mtk_smi_larb_of_ids[] = {
@@ -269,6 +259,10 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
                .compatible = "mediatek,mt2712-smi-larb",
                .data = &mtk_smi_larb_mt2712
        },
+       {
+               .compatible = "mediatek,mt8183-smi-larb",
+               .data = &mtk_smi_larb_mt8183
+       },
        {}
 };
 
@@ -279,7 +273,6 @@ static int mtk_smi_larb_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *smi_node;
        struct platform_device *smi_pdev;
-       int err;
 
        larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
        if (!larb)
@@ -298,16 +291,16 @@ static int mtk_smi_larb_probe(struct platform_device *pdev)
        larb->smi.clk_smi = devm_clk_get(dev, "smi");
        if (IS_ERR(larb->smi.clk_smi))
                return PTR_ERR(larb->smi.clk_smi);
-       larb->smi.dev = dev;
 
-       if (larb->larb_gen->need_larbid) {
-               err = of_property_read_u32(dev->of_node, "mediatek,larb-id",
-                                          &larb->larbid);
-               if (err) {
-                       dev_err(dev, "missing larbid property\n");
-                       return err;
-               }
+       if (larb->larb_gen->has_gals) {
+               /* The larbs may still haven't gals even if the SoC support.*/
+               larb->smi.clk_gals0 = devm_clk_get(dev, "gals");
+               if (PTR_ERR(larb->smi.clk_gals0) == -ENOENT)
+                       larb->smi.clk_gals0 = NULL;
+               else if (IS_ERR(larb->smi.clk_gals0))
+                       return PTR_ERR(larb->smi.clk_gals0);
        }
+       larb->smi.dev = dev;
 
        smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
        if (!smi_node)
@@ -336,27 +329,86 @@ static int mtk_smi_larb_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
+{
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+       const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
+       int ret;
+
+       /* Power on smi-common. */
+       ret = pm_runtime_get_sync(larb->smi_common_dev);
+       if (ret < 0) {
+               dev_err(dev, "Failed to pm get for smi-common(%d).\n", ret);
+               return ret;
+       }
+
+       ret = mtk_smi_clk_enable(&larb->smi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable clock(%d).\n", ret);
+               pm_runtime_put_sync(larb->smi_common_dev);
+               return ret;
+       }
+
+       /* Configure the basic setting for this larb */
+       larb_gen->config_port(dev);
+
+       return 0;
+}
+
+static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
+{
+       struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+       mtk_smi_clk_disable(&larb->smi);
+       pm_runtime_put_sync(larb->smi_common_dev);
+       return 0;
+}
+
+static const struct dev_pm_ops smi_larb_pm_ops = {
+       SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL)
+};
+
 static struct platform_driver mtk_smi_larb_driver = {
        .probe  = mtk_smi_larb_probe,
        .remove = mtk_smi_larb_remove,
        .driver = {
                .name = "mtk-smi-larb",
                .of_match_table = mtk_smi_larb_of_ids,
+               .pm             = &smi_larb_pm_ops,
        }
 };
 
+static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
+       .gen = MTK_SMI_GEN1,
+};
+
+static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
+       .gen = MTK_SMI_GEN2,
+};
+
+static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
+       .gen      = MTK_SMI_GEN2,
+       .has_gals = true,
+       .bus_sel  = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
+                   F_MMU1_LARB(7),
+};
+
 static const struct of_device_id mtk_smi_common_of_ids[] = {
        {
                .compatible = "mediatek,mt8173-smi-common",
-               .data = (void *)MTK_SMI_GEN2
+               .data = &mtk_smi_common_gen2,
        },
        {
                .compatible = "mediatek,mt2701-smi-common",
-               .data = (void *)MTK_SMI_GEN1
+               .data = &mtk_smi_common_gen1,
        },
        {
                .compatible = "mediatek,mt2712-smi-common",
-               .data = (void *)MTK_SMI_GEN2
+               .data = &mtk_smi_common_gen2,
+       },
+       {
+               .compatible = "mediatek,mt8183-smi-common",
+               .data = &mtk_smi_common_mt8183,
        },
        {}
 };
@@ -366,13 +418,13 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct mtk_smi *common;
        struct resource *res;
-       enum mtk_smi_gen smi_gen;
        int ret;
 
        common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
        if (!common)
                return -ENOMEM;
        common->dev = dev;
+       common->plat = of_device_get_match_data(dev);
 
        common->clk_apb = devm_clk_get(dev, "apb");
        if (IS_ERR(common->clk_apb))
@@ -382,14 +434,23 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
        if (IS_ERR(common->clk_smi))
                return PTR_ERR(common->clk_smi);
 
+       if (common->plat->has_gals) {
+               common->clk_gals0 = devm_clk_get(dev, "gals0");
+               if (IS_ERR(common->clk_gals0))
+                       return PTR_ERR(common->clk_gals0);
+
+               common->clk_gals1 = devm_clk_get(dev, "gals1");
+               if (IS_ERR(common->clk_gals1))
+                       return PTR_ERR(common->clk_gals1);
+       }
+
        /*
         * for mtk smi gen 1, we need to get the ao(always on) base to config
         * m4u port, and we need to enable the aync clock for transform the smi
         * clock into emi clock domain, but for mtk smi gen2, there's no smi ao
         * base.
         */
-       smi_gen = (enum mtk_smi_gen)of_device_get_match_data(dev);
-       if (smi_gen == MTK_SMI_GEN1) {
+       if (common->plat->gen == MTK_SMI_GEN1) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                common->smi_ao_base = devm_ioremap_resource(dev, res);
                if (IS_ERR(common->smi_ao_base))
@@ -402,6 +463,11 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
                ret = clk_prepare_enable(common->clk_async);
                if (ret)
                        return ret;
+       } else {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               common->base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(common->base))
+                       return PTR_ERR(common->base);
        }
        pm_runtime_enable(dev);
        platform_set_drvdata(pdev, common);
@@ -414,12 +480,42 @@ static int mtk_smi_common_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused mtk_smi_common_resume(struct device *dev)
+{
+       struct mtk_smi *common = dev_get_drvdata(dev);
+       u32 bus_sel = common->plat->bus_sel;
+       int ret;
+
+       ret = mtk_smi_clk_enable(common);
+       if (ret) {
+               dev_err(common->dev, "Failed to enable clock(%d).\n", ret);
+               return ret;
+       }
+
+       if (common->plat->gen == MTK_SMI_GEN2 && bus_sel)
+               writel(bus_sel, common->base + SMI_BUS_SEL);
+       return 0;
+}
+
+static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
+{
+       struct mtk_smi *common = dev_get_drvdata(dev);
+
+       mtk_smi_clk_disable(common);
+       return 0;
+}
+
+static const struct dev_pm_ops smi_common_pm_ops = {
+       SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL)
+};
+
 static struct platform_driver mtk_smi_common_driver = {
        .probe  = mtk_smi_common_probe,
        .remove = mtk_smi_common_remove,
        .driver = {
                .name = "mtk-smi-common",
                .of_match_table = mtk_smi_common_of_ids,
+               .pm             = &smi_common_pm_ops,
        }
 };
 
index 601cefb..050478c 100644 (file)
@@ -729,7 +729,7 @@ static int rk808_remove(struct i2c_client *client)
        return 0;
 }
 
-static int rk8xx_suspend(struct device *dev)
+static int __maybe_unused rk8xx_suspend(struct device *dev)
 {
        struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
        int ret = 0;
@@ -749,7 +749,7 @@ static int rk8xx_suspend(struct device *dev)
        return ret;
 }
 
-static int rk8xx_resume(struct device *dev)
+static int __maybe_unused rk8xx_resume(struct device *dev)
 {
        struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
        int ret = 0;
@@ -768,7 +768,7 @@ static int rk8xx_resume(struct device *dev)
 
        return ret;
 }
-SIMPLE_DEV_PM_OPS(rk8xx_pm_ops, rk8xx_suspend, rk8xx_resume);
+static SIMPLE_DEV_PM_OPS(rk8xx_pm_ops, rk8xx_suspend, rk8xx_resume);
 
 static struct i2c_driver rk808_i2c_driver = {
        .driver = {
index 6abfc8e..45b61b8 100644 (file)
@@ -126,18 +126,6 @@ config INTEL_MID_PTI
          an Intel Atom (non-netbook) mobile device containing a MIPI
          P1149.7 standard implementation.
 
-config SGI_IOC4
-       tristate "SGI IOC4 Base IO support"
-       depends on PCI
-       ---help---
-         This option enables basic support for the IOC4 chip on certain
-         SGI IO controller cards (IO9, IO10, and PCI-RT).  This option
-         does not enable any specific functions on such a card, but provides
-         necessary infrastructure for other drivers to utilize.
-
-         If you have an SGI Altix with an IOC4-based card say Y.
-         Otherwise say N.
-
 config TIFM_CORE
        tristate "TI Flash Media interface support"
        depends on PCI
@@ -200,9 +188,8 @@ config ENCLOSURE_SERVICES
 config SGI_XP
        tristate "Support communication between SGI SSIs"
        depends on NET
-       depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP
-       select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
-       select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
+       depends on (IA64_SGI_UV || X86_UV) && SMP
+       depends on X86_64 || BROKEN
        select SGI_GRU if X86_64 && SMP
        ---help---
          An SGI machine can be divided into multiple Single System
@@ -465,6 +452,7 @@ config PCI_ENDPOINT_TEST
 
 config XILINX_SDFEC
        tristate "Xilinx SDFEC 16"
+       depends on HAS_IOMEM
        help
          This option enables support for the Xilinx SDFEC (Soft Decision
          Forward Error Correction) driver. This enables a char driver
index abd8ae2..8dae0a9 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_QCOM_COINCELL)   += qcom-coincell.o
 obj-$(CONFIG_QCOM_FASTRPC)     += fastrpc.o
 obj-$(CONFIG_SENSORS_BH1770)   += bh1770glc.o
 obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
-obj-$(CONFIG_SGI_IOC4)         += ioc4.o
 obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
 obj-$(CONFIG_KGDB_TESTS)       += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
index 0c4894d..7a8f9d0 100644 (file)
@@ -970,7 +970,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
        rc = hl_ctx_init(hdev, hdev->kernel_ctx, true);
        if (rc) {
                dev_err(hdev->dev, "failed to initialize kernel context\n");
-               goto free_ctx;
+               kfree(hdev->kernel_ctx);
+               goto mmu_fini;
        }
 
        rc = hl_cb_pool_init(hdev);
@@ -1053,8 +1054,6 @@ release_ctx:
        if (hl_ctx_put(hdev->kernel_ctx) != 1)
                dev_err(hdev->dev,
                        "kernel ctx is still alive on initialization failure\n");
-free_ctx:
-       kfree(hdev->kernel_ctx);
 mmu_fini:
        hl_mmu_fini(hdev);
 eq_fini:
index a0e1817..271c5c8 100644 (file)
@@ -2729,9 +2729,10 @@ void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
                                GOYA_ASYNC_EVENT_ID_PI_UPDATE);
 }
 
-void goya_flush_pq_write(struct hl_device *hdev, u64 *pq, u64 exp_val)
+void goya_pqe_write(struct hl_device *hdev, __le64 *pqe, struct hl_bd *bd)
 {
-       /* Not needed in Goya */
+       /* The QMANs are on the SRAM so need to copy to IO space */
+       memcpy_toio((void __iomem *) pqe, bd, sizeof(struct hl_bd));
 }
 
 static void *goya_dma_alloc_coherent(struct hl_device *hdev, size_t size,
@@ -3313,9 +3314,11 @@ static int goya_validate_dma_pkt_no_mmu(struct hl_device *hdev,
        int rc;
 
        dev_dbg(hdev->dev, "DMA packet details:\n");
-       dev_dbg(hdev->dev, "source == 0x%llx\n", user_dma_pkt->src_addr);
-       dev_dbg(hdev->dev, "destination == 0x%llx\n", user_dma_pkt->dst_addr);
-       dev_dbg(hdev->dev, "size == %u\n", user_dma_pkt->tsize);
+       dev_dbg(hdev->dev, "source == 0x%llx\n",
+               le64_to_cpu(user_dma_pkt->src_addr));
+       dev_dbg(hdev->dev, "destination == 0x%llx\n",
+               le64_to_cpu(user_dma_pkt->dst_addr));
+       dev_dbg(hdev->dev, "size == %u\n", le32_to_cpu(user_dma_pkt->tsize));
 
        ctl = le32_to_cpu(user_dma_pkt->ctl);
        user_dir = (ctl & GOYA_PKT_LIN_DMA_CTL_DMA_DIR_MASK) >>
@@ -3344,9 +3347,11 @@ static int goya_validate_dma_pkt_mmu(struct hl_device *hdev,
                                struct packet_lin_dma *user_dma_pkt)
 {
        dev_dbg(hdev->dev, "DMA packet details:\n");
-       dev_dbg(hdev->dev, "source == 0x%llx\n", user_dma_pkt->src_addr);
-       dev_dbg(hdev->dev, "destination == 0x%llx\n", user_dma_pkt->dst_addr);
-       dev_dbg(hdev->dev, "size == %u\n", user_dma_pkt->tsize);
+       dev_dbg(hdev->dev, "source == 0x%llx\n",
+               le64_to_cpu(user_dma_pkt->src_addr));
+       dev_dbg(hdev->dev, "destination == 0x%llx\n",
+               le64_to_cpu(user_dma_pkt->dst_addr));
+       dev_dbg(hdev->dev, "size == %u\n", le32_to_cpu(user_dma_pkt->tsize));
 
        /*
         * WA for HW-23.
@@ -3386,7 +3391,8 @@ static int goya_validate_wreg32(struct hl_device *hdev,
 
        dev_dbg(hdev->dev, "WREG32 packet details:\n");
        dev_dbg(hdev->dev, "reg_offset == 0x%x\n", reg_offset);
-       dev_dbg(hdev->dev, "value      == 0x%x\n", wreg_pkt->value);
+       dev_dbg(hdev->dev, "value      == 0x%x\n",
+               le32_to_cpu(wreg_pkt->value));
 
        if (reg_offset != (mmDMA_CH_0_WR_COMP_ADDR_LO & 0x1FFF)) {
                dev_err(hdev->dev, "WREG32 packet with illegal address 0x%x\n",
@@ -3428,12 +3434,13 @@ static int goya_validate_cb(struct hl_device *hdev,
        while (cb_parsed_length < parser->user_cb_size) {
                enum packet_id pkt_id;
                u16 pkt_size;
-               void *user_pkt;
+               struct goya_packet *user_pkt;
 
-               user_pkt = (void *) (uintptr_t)
+               user_pkt = (struct goya_packet *) (uintptr_t)
                        (parser->user_cb->kernel_address + cb_parsed_length);
 
-               pkt_id = (enum packet_id) (((*(u64 *) user_pkt) &
+               pkt_id = (enum packet_id) (
+                               (le64_to_cpu(user_pkt->header) &
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
@@ -3453,7 +3460,8 @@ static int goya_validate_cb(struct hl_device *hdev,
                         * need to validate here as well because patch_cb() is
                         * not called in MMU path while this function is called
                         */
-                       rc = goya_validate_wreg32(hdev, parser, user_pkt);
+                       rc = goya_validate_wreg32(hdev,
+                               parser, (struct packet_wreg32 *) user_pkt);
                        break;
 
                case PACKET_WREG_BULK:
@@ -3481,10 +3489,10 @@ static int goya_validate_cb(struct hl_device *hdev,
                case PACKET_LIN_DMA:
                        if (is_mmu)
                                rc = goya_validate_dma_pkt_mmu(hdev, parser,
-                                               user_pkt);
+                                       (struct packet_lin_dma *) user_pkt);
                        else
                                rc = goya_validate_dma_pkt_no_mmu(hdev, parser,
-                                               user_pkt);
+                                       (struct packet_lin_dma *) user_pkt);
                        break;
 
                case PACKET_MSG_LONG:
@@ -3657,15 +3665,16 @@ static int goya_patch_cb(struct hl_device *hdev,
                enum packet_id pkt_id;
                u16 pkt_size;
                u32 new_pkt_size = 0;
-               void *user_pkt, *kernel_pkt;
+               struct goya_packet *user_pkt, *kernel_pkt;
 
-               user_pkt = (void *) (uintptr_t)
+               user_pkt = (struct goya_packet *) (uintptr_t)
                        (parser->user_cb->kernel_address + cb_parsed_length);
-               kernel_pkt = (void *) (uintptr_t)
+               kernel_pkt = (struct goya_packet *) (uintptr_t)
                        (parser->patched_cb->kernel_address +
                                        cb_patched_cur_length);
 
-               pkt_id = (enum packet_id) (((*(u64 *) user_pkt) &
+               pkt_id = (enum packet_id) (
+                               (le64_to_cpu(user_pkt->header) &
                                PACKET_HEADER_PACKET_ID_MASK) >>
                                        PACKET_HEADER_PACKET_ID_SHIFT);
 
@@ -3680,15 +3689,18 @@ static int goya_patch_cb(struct hl_device *hdev,
 
                switch (pkt_id) {
                case PACKET_LIN_DMA:
-                       rc = goya_patch_dma_packet(hdev, parser, user_pkt,
-                                               kernel_pkt, &new_pkt_size);
+                       rc = goya_patch_dma_packet(hdev, parser,
+                                       (struct packet_lin_dma *) user_pkt,
+                                       (struct packet_lin_dma *) kernel_pkt,
+                                       &new_pkt_size);
                        cb_patched_cur_length += new_pkt_size;
                        break;
 
                case PACKET_WREG_32:
                        memcpy(kernel_pkt, user_pkt, pkt_size);
                        cb_patched_cur_length += pkt_size;
-                       rc = goya_validate_wreg32(hdev, parser, kernel_pkt);
+                       rc = goya_validate_wreg32(hdev, parser,
+                                       (struct packet_wreg32 *) kernel_pkt);
                        break;
 
                case PACKET_WREG_BULK:
@@ -4352,6 +4364,8 @@ static int goya_unmask_irq_arr(struct hl_device *hdev, u32 *irq_arr,
        size_t total_pkt_size;
        long result;
        int rc;
+       int irq_num_entries, irq_arr_index;
+       __le32 *goya_irq_arr;
 
        total_pkt_size = sizeof(struct armcp_unmask_irq_arr_packet) +
                        irq_arr_size;
@@ -4369,8 +4383,16 @@ static int goya_unmask_irq_arr(struct hl_device *hdev, u32 *irq_arr,
        if (!pkt)
                return -ENOMEM;
 
-       pkt->length = cpu_to_le32(irq_arr_size / sizeof(irq_arr[0]));
-       memcpy(&pkt->irqs, irq_arr, irq_arr_size);
+       irq_num_entries = irq_arr_size / sizeof(irq_arr[0]);
+       pkt->length = cpu_to_le32(irq_num_entries);
+
+       /* We must perform any necessary endianness conversation on the irq
+        * array being passed to the goya hardware
+        */
+       for (irq_arr_index = 0, goya_irq_arr = (__le32 *) &pkt->irqs;
+                       irq_arr_index < irq_num_entries ; irq_arr_index++)
+               goya_irq_arr[irq_arr_index] =
+                               cpu_to_le32(irq_arr[irq_arr_index]);
 
        pkt->armcp_pkt.ctl = cpu_to_le32(ARMCP_PACKET_UNMASK_RAZWI_IRQ_ARRAY <<
                                                ARMCP_PKT_CTL_OPCODE_SHIFT);
@@ -5042,7 +5064,7 @@ static const struct hl_asic_funcs goya_funcs = {
        .resume = goya_resume,
        .cb_mmap = goya_cb_mmap,
        .ring_doorbell = goya_ring_doorbell,
-       .flush_pq_write = goya_flush_pq_write,
+       .pqe_write = goya_pqe_write,
        .asic_dma_alloc_coherent = goya_dma_alloc_coherent,
        .asic_dma_free_coherent = goya_dma_free_coherent,
        .get_int_queue_base = goya_get_int_queue_base,
index f8c6118..d7f48c9 100644 (file)
@@ -177,7 +177,7 @@ int goya_late_init(struct hl_device *hdev);
 void goya_late_fini(struct hl_device *hdev);
 
 void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi);
-void goya_flush_pq_write(struct hl_device *hdev, u64 *pq, u64 exp_val);
+void goya_pqe_write(struct hl_device *hdev, __le64 *pqe, struct hl_bd *bd);
 void goya_update_eq_ci(struct hl_device *hdev, u32 val);
 void goya_restore_phase_topology(struct hl_device *hdev);
 int goya_context_switch(struct hl_device *hdev, u32 asid);
index 6a4c64b..ce83ada 100644 (file)
@@ -441,7 +441,11 @@ enum hl_pll_frequency {
  * @resume: handles IP specific H/W or SW changes for resume.
  * @cb_mmap: maps a CB.
  * @ring_doorbell: increment PI on a given QMAN.
- * @flush_pq_write: flush PQ entry write if necessary, WARN if flushing failed.
+ * @pqe_write: Write the PQ entry to the PQ. This is ASIC-specific
+ *             function because the PQs are located in different memory areas
+ *             per ASIC (SRAM, DRAM, Host memory) and therefore, the method of
+ *             writing the PQE must match the destination memory area
+ *             properties.
  * @asic_dma_alloc_coherent: Allocate coherent DMA memory by calling
  *                           dma_alloc_coherent(). This is ASIC function because
  *                           its implementation is not trivial when the driver
@@ -510,7 +514,8 @@ struct hl_asic_funcs {
        int (*cb_mmap)(struct hl_device *hdev, struct vm_area_struct *vma,
                        u64 kaddress, phys_addr_t paddress, u32 size);
        void (*ring_doorbell)(struct hl_device *hdev, u32 hw_queue_id, u32 pi);
-       void (*flush_pq_write)(struct hl_device *hdev, u64 *pq, u64 exp_val);
+       void (*pqe_write)(struct hl_device *hdev, __le64 *pqe,
+                       struct hl_bd *bd);
        void* (*asic_dma_alloc_coherent)(struct hl_device *hdev, size_t size,
                                        dma_addr_t *dma_handle, gfp_t flag);
        void (*asic_dma_free_coherent)(struct hl_device *hdev, size_t size,
index e3b5517..5f5673b 100644 (file)
@@ -290,23 +290,19 @@ static void int_hw_queue_schedule_job(struct hl_cs_job *job)
        struct hl_device *hdev = job->cs->ctx->hdev;
        struct hl_hw_queue *q = &hdev->kernel_queues[job->hw_queue_id];
        struct hl_bd bd;
-       u64 *pi, *pbd = (u64 *) &bd;
+       __le64 *pi;
 
        bd.ctl = 0;
-       bd.len = __cpu_to_le32(job->job_cb_size);
-       bd.ptr = __cpu_to_le64((u64) (uintptr_t) job->user_cb);
+       bd.len = cpu_to_le32(job->job_cb_size);
+       bd.ptr = cpu_to_le64((u64) (uintptr_t) job->user_cb);
 
-       pi = (u64 *) (uintptr_t) (q->kernel_address +
+       pi = (__le64 *) (uintptr_t) (q->kernel_address +
                ((q->pi & (q->int_queue_len - 1)) * sizeof(bd)));
 
-       pi[0] = pbd[0];
-       pi[1] = pbd[1];
-
        q->pi++;
        q->pi &= ((q->int_queue_len << 1) - 1);
 
-       /* Flush PQ entry write. Relevant only for specific ASICs */
-       hdev->asic_funcs->flush_pq_write(hdev, pi, pbd[0]);
+       hdev->asic_funcs->pqe_write(hdev, pi, &bd);
 
        hdev->asic_funcs->ring_doorbell(hdev, q->hw_queue_id, q->pi);
 }
index a14407b..ef54bad 100644 (file)
@@ -52,6 +52,19 @@ enum goya_dma_direction {
 #define GOYA_PKT_CTL_MB_SHIFT          31
 #define GOYA_PKT_CTL_MB_MASK           0x80000000
 
+/* All packets have, at least, an 8-byte header, which contains
+ * the packet type. The kernel driver uses the packet header for packet
+ * validation and to perform any necessary required preparation before
+ * sending them off to the hardware.
+ */
+struct goya_packet {
+       __le64 header;
+       /* The rest of the packet data follows. Use the corresponding
+        * packet_XXX struct to deference the data, based on packet type
+        */
+       u8 contents[0];
+};
+
 struct packet_nop {
        __le32 reserved;
        __le32 ctl;
index ea9f72f..199791b 100644 (file)
@@ -80,8 +80,7 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
        struct hl_cs_job *job;
        bool shadow_index_valid;
        u16 shadow_index;
-       u32 *cq_entry;
-       u32 *cq_base;
+       struct hl_cq_entry *cq_entry, *cq_base;
 
        if (hdev->disabled) {
                dev_dbg(hdev->dev,
@@ -90,29 +89,29 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
                return IRQ_HANDLED;
        }
 
-       cq_base = (u32 *) (uintptr_t) cq->kernel_address;
+       cq_base = (struct hl_cq_entry *) (uintptr_t) cq->kernel_address;
 
        while (1) {
-               bool entry_ready = ((cq_base[cq->ci] & CQ_ENTRY_READY_MASK)
+               bool entry_ready = ((le32_to_cpu(cq_base[cq->ci].data) &
+                                       CQ_ENTRY_READY_MASK)
                                                >> CQ_ENTRY_READY_SHIFT);
 
                if (!entry_ready)
                        break;
 
-               cq_entry = (u32 *) &cq_base[cq->ci];
+               cq_entry = (struct hl_cq_entry *) &cq_base[cq->ci];
 
-               /*
-                * Make sure we read CQ entry contents after we've
+               /* Make sure we read CQ entry contents after we've
                 * checked the ownership bit.
                 */
                dma_rmb();
 
-               shadow_index_valid =
-                       ((*cq_entry & CQ_ENTRY_SHADOW_INDEX_VALID_MASK)
+               shadow_index_valid = ((le32_to_cpu(cq_entry->data) &
+                                       CQ_ENTRY_SHADOW_INDEX_VALID_MASK)
                                        >> CQ_ENTRY_SHADOW_INDEX_VALID_SHIFT);
 
-               shadow_index = (u16)
-                       ((*cq_entry & CQ_ENTRY_SHADOW_INDEX_MASK)
+               shadow_index = (u16) ((le32_to_cpu(cq_entry->data) &
+                                       CQ_ENTRY_SHADOW_INDEX_MASK)
                                        >> CQ_ENTRY_SHADOW_INDEX_SHIFT);
 
                queue = &hdev->kernel_queues[cq->hw_queue_id];
@@ -122,8 +121,7 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
                        queue_work(hdev->cq_wq, &job->finish_work);
                }
 
-               /*
-                * Update ci of the context's queue. There is no
+               /* Update ci of the context's queue. There is no
                 * need to protect it with spinlock because this update is
                 * done only inside IRQ and there is a different IRQ per
                 * queue
@@ -131,7 +129,8 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
                queue->ci = hl_queue_inc_ptr(queue->ci);
 
                /* Clear CQ entry ready bit */
-               cq_base[cq->ci] &= ~CQ_ENTRY_READY_MASK;
+               cq_entry->data = cpu_to_le32(le32_to_cpu(cq_entry->data) &
+                                               ~CQ_ENTRY_READY_MASK);
 
                cq->ci = hl_cq_inc_ptr(cq->ci);
 
index 42d237c..365fb0c 100644 (file)
@@ -1629,6 +1629,8 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx)
                        dev_dbg(hdev->dev,
                                "page list 0x%p of asid %d is still alive\n",
                                phys_pg_list, ctx->asid);
+                       atomic64_sub(phys_pg_list->total_size,
+                                       &hdev->dram_used_mem);
                        free_phys_pg_pack(hdev, phys_pg_list);
                        idr_remove(&vm->phys_pg_pack_handles, i);
                }
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
deleted file mode 100644 (file)
index 9d0445a..0000000
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2005-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/* This file contains the master driver module for use by SGI IOC4 subdrivers.
- *
- * It allocates any resources shared between multiple subdevices, and
- * provides accessor functions (where needed) and the like for those
- * resources.  It also provides a mechanism for the subdevice modules
- * to support loading and unloading.
- *
- * Non-shared resources (e.g. external interrupt A_INT_OUT register page
- * alias, serial port and UART registers) are handled by the subdevice
- * modules themselves.
- *
- * This is all necessary because IOC4 is not implemented as a multi-function
- * PCI device, but an amalgamation of disparate registers for several
- * types of device (ATA, serial, external interrupts).  The normal
- * resource management in the kernel doesn't have quite the right interfaces
- * to handle this situation (e.g. multiple modules can't claim the same
- * PCI ID), thus this IOC4 master module.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/ktime.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/time.h>
-#include <asm/io.h>
-
-/***************
- * Definitions *
- ***************/
-
-/* Tweakable values */
-
-/* PCI bus speed detection/calibration */
-#define IOC4_CALIBRATE_COUNT 63                /* Calibration cycle period */
-#define IOC4_CALIBRATE_CYCLES 256      /* Average over this many cycles */
-#define IOC4_CALIBRATE_DISCARD 2       /* Discard first few cycles */
-#define IOC4_CALIBRATE_LOW_MHZ 25      /* Lower bound on bus speed sanity */
-#define IOC4_CALIBRATE_HIGH_MHZ 75     /* Upper bound on bus speed sanity */
-#define IOC4_CALIBRATE_DEFAULT_MHZ 66  /* Assumed if sanity check fails */
-
-/************************
- * Submodule management *
- ************************/
-
-static DEFINE_MUTEX(ioc4_mutex);
-
-static LIST_HEAD(ioc4_devices);
-static LIST_HEAD(ioc4_submodules);
-
-/* Register an IOC4 submodule */
-int
-ioc4_register_submodule(struct ioc4_submodule *is)
-{
-       struct ioc4_driver_data *idd;
-
-       mutex_lock(&ioc4_mutex);
-       list_add(&is->is_list, &ioc4_submodules);
-
-       /* Initialize submodule for each IOC4 */
-       if (!is->is_probe)
-               goto out;
-
-       list_for_each_entry(idd, &ioc4_devices, idd_list) {
-               if (is->is_probe(idd)) {
-                       printk(KERN_WARNING
-                              "%s: IOC4 submodule %s probe failed "
-                              "for pci_dev %s",
-                              __func__, module_name(is->is_owner),
-                              pci_name(idd->idd_pdev));
-               }
-       }
- out:
-       mutex_unlock(&ioc4_mutex);
-       return 0;
-}
-
-/* Unregister an IOC4 submodule */
-void
-ioc4_unregister_submodule(struct ioc4_submodule *is)
-{
-       struct ioc4_driver_data *idd;
-
-       mutex_lock(&ioc4_mutex);
-       list_del(&is->is_list);
-
-       /* Remove submodule for each IOC4 */
-       if (!is->is_remove)
-               goto out;
-
-       list_for_each_entry(idd, &ioc4_devices, idd_list) {
-               if (is->is_remove(idd)) {
-                       printk(KERN_WARNING
-                              "%s: IOC4 submodule %s remove failed "
-                              "for pci_dev %s.\n",
-                              __func__, module_name(is->is_owner),
-                              pci_name(idd->idd_pdev));
-               }
-       }
- out:
-       mutex_unlock(&ioc4_mutex);
-}
-
-/*********************
- * Device management *
- *********************/
-
-#define IOC4_CALIBRATE_LOW_LIMIT \
-       (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
-#define IOC4_CALIBRATE_HIGH_LIMIT \
-       (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
-#define IOC4_CALIBRATE_DEFAULT \
-       (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
-
-#define IOC4_CALIBRATE_END \
-       (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
-
-#define IOC4_INT_OUT_MODE_TOGGLE 0x7   /* Toggle INT_OUT every COUNT+1 ticks */
-
-/* Determines external interrupt output clock period of the PCI bus an
- * IOC4 is attached to.  This value can be used to determine the PCI
- * bus speed.
- *
- * IOC4 has a design feature that various internal timers are derived from
- * the PCI bus clock.  This causes IOC4 device drivers to need to take the
- * bus speed into account when setting various register values (e.g. INT_OUT
- * register COUNT field, UART divisors, etc).  Since this information is
- * needed by several subdrivers, it is determined by the main IOC4 driver,
- * even though the following code utilizes external interrupt registers
- * to perform the speed calculation.
- */
-static void
-ioc4_clock_calibrate(struct ioc4_driver_data *idd)
-{
-       union ioc4_int_out int_out;
-       union ioc4_gpcr gpcr;
-       unsigned int state, last_state;
-       uint64_t start, end, period;
-       unsigned int count;
-
-       /* Enable output */
-       gpcr.raw = 0;
-       gpcr.fields.dir = IOC4_GPCR_DIR_0;
-       gpcr.fields.int_out_en = 1;
-       writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
-
-       /* Reset to power-on state */
-       writel(0, &idd->idd_misc_regs->int_out.raw);
-
-       /* Set up square wave */
-       int_out.raw = 0;
-       int_out.fields.count = IOC4_CALIBRATE_COUNT;
-       int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
-       int_out.fields.diag = 0;
-       writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
-
-       /* Check square wave period averaged over some number of cycles */
-       start = ktime_get_ns();
-       state = 1; /* make sure the first read isn't a rising edge */
-       for (count = 0; count <= IOC4_CALIBRATE_END; count++) {
-               do { /* wait for a rising edge */
-                       last_state = state;
-                       int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
-                       state = int_out.fields.int_out;
-               } while (last_state || !state);
-
-               /* discard the first few cycles */
-               if (count == IOC4_CALIBRATE_DISCARD)
-                       start = ktime_get_ns();
-       }
-       end = ktime_get_ns();
-
-       /* Calculation rearranged to preserve intermediate precision.
-        * Logically:
-        * 1. "end - start" gives us the measurement period over all
-        *    the square wave cycles.
-        * 2. Divide by number of square wave cycles to get the period
-        *    of a square wave cycle.
-        * 3. Divide by 2*(int_out.fields.count+1), which is the formula
-        *    by which the IOC4 generates the square wave, to get the
-        *    period of an IOC4 INT_OUT count.
-        */
-       period = (end - start) /
-               (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));
-
-       /* Bounds check the result. */
-       if (period > IOC4_CALIBRATE_LOW_LIMIT ||
-           period < IOC4_CALIBRATE_HIGH_LIMIT) {
-               printk(KERN_INFO
-                      "IOC4 %s: Clock calibration failed.  Assuming"
-                      "PCI clock is %d ns.\n",
-                      pci_name(idd->idd_pdev),
-                      IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
-               period = IOC4_CALIBRATE_DEFAULT;
-       } else {
-               u64 ns = period;
-
-               do_div(ns, IOC4_EXTINT_COUNT_DIVISOR);
-               printk(KERN_DEBUG
-                      "IOC4 %s: PCI clock is %llu ns.\n",
-                      pci_name(idd->idd_pdev), (unsigned long long)ns);
-       }
-
-       /* Remember results.  We store the extint clock period rather
-        * than the PCI clock period so that greater precision is
-        * retained.  Divide by IOC4_EXTINT_COUNT_DIVISOR to get
-        * PCI clock period.
-        */
-       idd->count_period = period;
-}
-
-/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
- * Each brings out different combinations of IOC4 signals, thus.
- * the IOC4 subdrivers need to know to which we're attached.
- *
- * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
- * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
- * If neither is present, it's a PCI-RT.
- */
-static unsigned int
-ioc4_variant(struct ioc4_driver_data *idd)
-{
-       struct pci_dev *pdev = NULL;
-       int found = 0;
-
-       /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
-       do {
-               pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
-                                     PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
-               if (pdev &&
-                   idd->idd_pdev->bus->number == pdev->bus->number &&
-                   3 == PCI_SLOT(pdev->devfn))
-                       found = 1;
-       } while (pdev && !found);
-       if (NULL != pdev) {
-               pci_dev_put(pdev);
-               return IOC4_VARIANT_IO9;
-       }
-
-       /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
-       pdev = NULL;
-       do {
-               pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
-                                     PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
-               if (pdev &&
-                   idd->idd_pdev->bus->number == pdev->bus->number &&
-                   3 == PCI_SLOT(pdev->devfn))
-                       found = 1;
-       } while (pdev && !found);
-       if (NULL != pdev) {
-               pci_dev_put(pdev);
-               return IOC4_VARIANT_IO10;
-       }
-
-       /* PCI-RT: No SCSI/SATA controller will be present */
-       return IOC4_VARIANT_PCI_RT;
-}
-
-static void
-ioc4_load_modules(struct work_struct *work)
-{
-       request_module("sgiioc4");
-}
-
-static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules);
-
-/* Adds a new instance of an IOC4 card */
-static int
-ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
-       struct ioc4_driver_data *idd;
-       struct ioc4_submodule *is;
-       uint32_t pcmd;
-       int ret;
-
-       /* Enable IOC4 and take ownership of it */
-       if ((ret = pci_enable_device(pdev))) {
-               printk(KERN_WARNING
-                      "%s: Failed to enable IOC4 device for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               goto out;
-       }
-       pci_set_master(pdev);
-
-       /* Set up per-IOC4 data */
-       idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
-       if (!idd) {
-               printk(KERN_WARNING
-                      "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               ret = -ENODEV;
-               goto out_idd;
-       }
-       idd->idd_pdev = pdev;
-       idd->idd_pci_id = pci_id;
-
-       /* Map IOC4 misc registers.  These are shared between subdevices
-        * so the main IOC4 module manages them.
-        */
-       idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
-       if (!idd->idd_bar0) {
-               printk(KERN_WARNING
-                      "%s: Unable to find IOC4 misc resource "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(idd->idd_pdev));
-               ret = -ENODEV;
-               goto out_pci;
-       }
-       if (!request_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
-                           "ioc4_misc")) {
-               printk(KERN_WARNING
-                      "%s: Unable to request IOC4 misc region "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(idd->idd_pdev));
-               ret = -ENODEV;
-               goto out_pci;
-       }
-       idd->idd_misc_regs = ioremap(idd->idd_bar0,
-                                    sizeof(struct ioc4_misc_regs));
-       if (!idd->idd_misc_regs) {
-               printk(KERN_WARNING
-                      "%s: Unable to remap IOC4 misc region "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(idd->idd_pdev));
-               ret = -ENODEV;
-               goto out_misc_region;
-       }
-
-       /* Failsafe portion of per-IOC4 initialization */
-
-       /* Detect card variant */
-       idd->idd_variant = ioc4_variant(idd);
-       printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
-              idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
-              idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
-              idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
-
-       /* Initialize IOC4 */
-       pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
-       pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
-                              pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
-
-       /* Determine PCI clock */
-       ioc4_clock_calibrate(idd);
-
-       /* Disable/clear all interrupts.  Need to do this here lest
-        * one submodule request the shared IOC4 IRQ, but interrupt
-        * is generated by a different subdevice.
-        */
-       /* Disable */
-       writel(~0, &idd->idd_misc_regs->other_iec.raw);
-       writel(~0, &idd->idd_misc_regs->sio_iec);
-       /* Clear (i.e. acknowledge) */
-       writel(~0, &idd->idd_misc_regs->other_ir.raw);
-       writel(~0, &idd->idd_misc_regs->sio_ir);
-
-       /* Track PCI-device specific data */
-       idd->idd_serial_data = NULL;
-       pci_set_drvdata(idd->idd_pdev, idd);
-
-       mutex_lock(&ioc4_mutex);
-       list_add_tail(&idd->idd_list, &ioc4_devices);
-
-       /* Add this IOC4 to all submodules */
-       list_for_each_entry(is, &ioc4_submodules, is_list) {
-               if (is->is_probe && is->is_probe(idd)) {
-                       printk(KERN_WARNING
-                              "%s: IOC4 submodule 0x%s probe failed "
-                              "for pci_dev %s.\n",
-                              __func__, module_name(is->is_owner),
-                              pci_name(idd->idd_pdev));
-               }
-       }
-       mutex_unlock(&ioc4_mutex);
-
-       /* Request sgiioc4 IDE driver on boards that bring that functionality
-        * off of IOC4.  The root filesystem may be hosted on a drive connected
-        * to IOC4, so we need to make sure the sgiioc4 driver is loaded as it
-        * won't be picked up by modprobes due to the ioc4 module owning the
-        * PCI device.
-        */
-       if (idd->idd_variant != IOC4_VARIANT_PCI_RT) {
-               /* Request the module from a work procedure as the modprobe
-                * goes out to a userland helper and that will hang if done
-                * directly from ioc4_probe().
-                */
-               printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
-               schedule_work(&ioc4_load_modules_work);
-       }
-
-       return 0;
-
-out_misc_region:
-       release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
-out_pci:
-       kfree(idd);
-out_idd:
-       pci_disable_device(pdev);
-out:
-       return ret;
-}
-
-/* Removes a particular instance of an IOC4 card. */
-static void
-ioc4_remove(struct pci_dev *pdev)
-{
-       struct ioc4_submodule *is;
-       struct ioc4_driver_data *idd;
-
-       idd = pci_get_drvdata(pdev);
-
-       /* Remove this IOC4 from all submodules */
-       mutex_lock(&ioc4_mutex);
-       list_for_each_entry(is, &ioc4_submodules, is_list) {
-               if (is->is_remove && is->is_remove(idd)) {
-                       printk(KERN_WARNING
-                              "%s: IOC4 submodule 0x%s remove failed "
-                              "for pci_dev %s.\n",
-                              __func__, module_name(is->is_owner),
-                              pci_name(idd->idd_pdev));
-               }
-       }
-       mutex_unlock(&ioc4_mutex);
-
-       /* Release resources */
-       iounmap(idd->idd_misc_regs);
-       if (!idd->idd_bar0) {
-               printk(KERN_WARNING
-                      "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
-                      "Device removal may be incomplete.\n",
-                      __func__, pci_name(idd->idd_pdev));
-       }
-       release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
-
-       /* Disable IOC4 and relinquish */
-       pci_disable_device(pdev);
-
-       /* Remove and free driver data */
-       mutex_lock(&ioc4_mutex);
-       list_del(&idd->idd_list);
-       mutex_unlock(&ioc4_mutex);
-       kfree(idd);
-}
-
-static const struct pci_device_id ioc4_id_table[] = {
-       {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
-        PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
-       {0}
-};
-
-static struct pci_driver ioc4_driver = {
-       .name = "IOC4",
-       .id_table = ioc4_id_table,
-       .probe = ioc4_probe,
-       .remove = ioc4_remove,
-};
-
-MODULE_DEVICE_TABLE(pci, ioc4_id_table);
-
-/*********************
- * Module management *
- *********************/
-
-/* Module load */
-static int __init
-ioc4_init(void)
-{
-       return pci_register_driver(&ioc4_driver);
-}
-
-/* Module unload */
-static void __exit
-ioc4_exit(void)
-{
-       /* Ensure ioc4_load_modules() has completed before exiting */
-       flush_work(&ioc4_load_modules_work);
-       pci_unregister_driver(&ioc4_driver);
-}
-
-module_init(ioc4_init);
-module_exit(ioc4_exit);
-
-MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>");
-MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ioc4_register_submodule);
-EXPORT_SYMBOL(ioc4_unregister_submodule);
index 1606658..24245cc 100644 (file)
@@ -22,7 +22,7 @@ struct lkdtm_list {
  * recurse past the end of THREAD_SIZE by default.
  */
 #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
-#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2)
+#define REC_STACK_SIZE (_AC(CONFIG_FRAME_WARN, UL) / 2)
 #else
 #define REC_STACK_SIZE (THREAD_SIZE / 8)
 #endif
@@ -91,7 +91,7 @@ void lkdtm_LOOP(void)
 
 void lkdtm_EXHAUST_STACK(void)
 {
-       pr_info("Calling function with %d frame size to depth %d ...\n",
+       pr_info("Calling function with %lu frame size to depth %d ...\n",
                REC_STACK_SIZE, recur_count);
        recursive_loop(recur_count);
        pr_info("FAIL: survived without exhausting stack?!\n");
index 6c01737..77f7dff 100644 (file)
@@ -81,6 +81,8 @@
 
 #define MEI_DEV_ID_ICP_LP     0x34E0  /* Ice Lake Point LP */
 
+#define MEI_DEV_ID_TGP_LP     0xA0E0  /* Tiger Lake Point LP */
+
 #define MEI_DEV_ID_MCC        0x4B70  /* Mule Creek Canyon (EHL) */
 #define MEI_DEV_ID_MCC_4      0x4B75  /* Mule Creek Canyon 4 (EHL) */
 
index 57cb68f..541538e 100644 (file)
@@ -98,6 +98,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
 
        {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
 
+       {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)},
+
        {MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH12_CFG)},
        {MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
 
index bbb622c..34c55a4 100644 (file)
@@ -4,17 +4,10 @@
 #
 
 obj-$(CONFIG_SGI_XP)           += xp.o
-xp-y                           := xp_main.o
-xp-$(CONFIG_IA64_SGI_SN2)      += xp_sn2.o xp_nofault.o
-xp-$(CONFIG_IA64_GENERIC)      += xp_sn2.o xp_nofault.o
-xp-$(CONFIG_IA64_SGI_UV)       += xp_uv.o
-xp-$(CONFIG_X86_64)            += xp_uv.o
+xp-y                           := xp_main.o xp_uv.o
 
 obj-$(CONFIG_SGI_XP)           += xpc.o
-xpc-y                          := xpc_main.o xpc_channel.o xpc_partition.o
-xpc-$(CONFIG_IA64_SGI_SN2)     += xpc_sn2.o
-xpc-$(CONFIG_IA64_GENERIC)     += xpc_sn2.o
-xpc-$(CONFIG_IA64_SGI_UV)      += xpc_uv.o
-xpc-$(CONFIG_X86_64)           += xpc_uv.o
+xpc-y                          := xpc_main.o xpc_channel.o xpc_partition.o \
+                                  xpc_uv.o
 
 obj-$(CONFIG_SGI_XP)           += xpnet.o
index b8069ee..06469b1 100644 (file)
 #define is_uv()                0
 #endif
 
-#if defined CONFIG_IA64
-#include <asm/sn/arch.h>       /* defines is_shub1() and is_shub2() */
-#define is_shub()      ia64_platform_is("sn2")
-#endif
-
-#ifndef is_shub1
-#define is_shub1()     0
-#endif
-
-#ifndef is_shub2
-#define is_shub2()     0
-#endif
-
-#ifndef is_shub
-#define is_shub()      0
-#endif
-
 #ifdef USE_DBUG_ON
 #define DBUG_ON(condition)     BUG_ON(condition)
 #else
@@ -360,9 +343,7 @@ extern int xp_nofault_PIOR(void *);
 extern int xp_error_PIOR(void);
 
 extern struct device *xp;
-extern enum xp_retval xp_init_sn2(void);
 extern enum xp_retval xp_init_uv(void);
-extern void xp_exit_sn2(void);
 extern void xp_exit_uv(void);
 
 #endif /* _DRIVERS_MISC_SGIXP_XP_H */
index 6d7f557..5fd94d8 100644 (file)
@@ -233,9 +233,7 @@ xp_init(void)
        for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++)
                mutex_init(&xpc_registrations[ch_number].mutex);
 
-       if (is_shub())
-               ret = xp_init_sn2();
-       else if (is_uv())
+       if (is_uv())
                ret = xp_init_uv();
        else
                ret = 0;
@@ -251,9 +249,7 @@ module_init(xp_init);
 void __exit
 xp_exit(void)
 {
-       if (is_shub())
-               xp_exit_sn2();
-       else if (is_uv())
+       if (is_uv())
                xp_exit_uv();
 }
 
diff --git a/drivers/misc/sgi-xp/xp_nofault.S b/drivers/misc/sgi-xp/xp_nofault.S
deleted file mode 100644 (file)
index e38d433..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * The xp_nofault_PIOR function takes a pointer to a remote PIO register
- * and attempts to load and consume a value from it.  This function
- * will be registered as a nofault code block.  In the event that the
- * PIO read fails, the MCA handler will force the error to look
- * corrected and vector to the xp_error_PIOR which will return an error.
- *
- * The definition of "consumption" and the time it takes for an MCA
- * to surface is processor implementation specific.  This code
- * is sufficient on Itanium through the Montvale processor family.
- * It may need to be adjusted for future processor implementations.
- *
- *     extern int xp_nofault_PIOR(void *remote_register);
- */
-
-       .global xp_nofault_PIOR
-xp_nofault_PIOR:
-       mov     r8=r0                   // Stage a success return value
-       ld8.acq r9=[r32];;              // PIO Read the specified register
-       adds    r9=1,r9;;               // Add to force consumption
-       srlz.i;;                        // Allow time for MCA to surface
-       br.ret.sptk.many b0;;           // Return success
-
-       .global xp_error_PIOR
-xp_error_PIOR:
-       mov     r8=1                    // Return value of 1
-       br.ret.sptk.many b0;;           // Return failure
diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c
deleted file mode 100644 (file)
index d8e463f..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * Cross Partition (XP) sn2-based functions.
- *
- *      Architecture specific implementation of common functions.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/sn_sal.h>
-#include "xp.h"
-
-/*
- * The export of xp_nofault_PIOR needs to happen here since it is defined
- * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is
- * defined here.
- */
-EXPORT_SYMBOL_GPL(xp_nofault_PIOR);
-
-u64 xp_nofault_PIOR_target;
-EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target);
-
-/*
- * Register a nofault code region which performs a cross-partition PIO read.
- * If the PIO read times out, the MCA handler will consume the error and
- * return to a kernel-provided instruction to indicate an error. This PIO read
- * exists because it is guaranteed to timeout if the destination is down
- * (amo operations do not timeout on at least some CPUs on Shubs <= v1.2,
- * which unfortunately we have to work around).
- */
-static enum xp_retval
-xp_register_nofault_code_sn2(void)
-{
-       int ret;
-       u64 func_addr;
-       u64 err_func_addr;
-
-       func_addr = *(u64 *)xp_nofault_PIOR;
-       err_func_addr = *(u64 *)xp_error_PIOR;
-       ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr,
-                                      1, 1);
-       if (ret != 0) {
-               dev_err(xp, "can't register nofault code, error=%d\n", ret);
-               return xpSalError;
-       }
-       /*
-        * Setup the nofault PIO read target. (There is no special reason why
-        * SH_IPI_ACCESS was selected.)
-        */
-       if (is_shub1())
-               xp_nofault_PIOR_target = SH1_IPI_ACCESS;
-       else if (is_shub2())
-               xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
-
-       return xpSuccess;
-}
-
-static void
-xp_unregister_nofault_code_sn2(void)
-{
-       u64 func_addr = *(u64 *)xp_nofault_PIOR;
-       u64 err_func_addr = *(u64 *)xp_error_PIOR;
-
-       /* unregister the PIO read nofault code region */
-       (void)sn_register_nofault_code(func_addr, err_func_addr,
-                                      err_func_addr, 1, 0);
-}
-
-/*
- * Convert a virtual memory address to a physical memory address.
- */
-static unsigned long
-xp_pa_sn2(void *addr)
-{
-       return __pa(addr);
-}
-
-/*
- * Convert a global physical to a socket physical address.
- */
-static unsigned long
-xp_socket_pa_sn2(unsigned long gpa)
-{
-       return gpa;
-}
-
-/*
- * Wrapper for bte_copy().
- *
- *     dst_pa - physical address of the destination of the transfer.
- *     src_pa - physical address of the source of the transfer.
- *     len - number of bytes to transfer from source to destination.
- *
- * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock.
- */
-static enum xp_retval
-xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa,
-                    size_t len)
-{
-       bte_result_t ret;
-
-       ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
-       if (ret == BTE_SUCCESS)
-               return xpSuccess;
-
-       if (is_shub2()) {
-               dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa="
-                       "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa,
-                       src_pa, len);
-       } else {
-               dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx "
-                       "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len);
-       }
-
-       return xpBteCopyError;
-}
-
-static int
-xp_cpu_to_nasid_sn2(int cpuid)
-{
-       return cpuid_to_nasid(cpuid);
-}
-
-static enum xp_retval
-xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size)
-{
-       u64 nasid_array = 0;
-       int ret;
-
-       ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
-                                  &nasid_array);
-       if (ret != 0) {
-               dev_err(xp, "sn_change_memprotect(,, "
-                       "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
-               return xpSalError;
-       }
-       return xpSuccess;
-}
-
-static enum xp_retval
-xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size)
-{
-       u64 nasid_array = 0;
-       int ret;
-
-       ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
-                                  &nasid_array);
-       if (ret != 0) {
-               dev_err(xp, "sn_change_memprotect(,, "
-                       "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
-               return xpSalError;
-       }
-       return xpSuccess;
-}
-
-enum xp_retval
-xp_init_sn2(void)
-{
-       BUG_ON(!is_shub());
-
-       xp_max_npartitions = XP_MAX_NPARTITIONS_SN2;
-       xp_partition_id = sn_partition_id;
-       xp_region_size = sn_region_size;
-
-       xp_pa = xp_pa_sn2;
-       xp_socket_pa = xp_socket_pa_sn2;
-       xp_remote_memcpy = xp_remote_memcpy_sn2;
-       xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;
-       xp_expand_memprotect = xp_expand_memprotect_sn2;
-       xp_restrict_memprotect = xp_restrict_memprotect_sn2;
-
-       return xp_register_nofault_code_sn2();
-}
-
-void
-xp_exit_sn2(void)
-{
-       BUG_ON(!is_shub());
-
-       xp_unregister_nofault_code_sn2();
-}
-
index a0d0932..f15a9f2 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/uv/uv_hub.h>
 #if defined CONFIG_X86_64
 #include <asm/uv/bios.h>
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
 #include <asm/sn/sn_sal.h>
 #endif
 #include "../sgi-gru/grukservices.h"
@@ -99,7 +99,7 @@ xp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size)
                return xpBiosError;
        }
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        u64 nasid_array;
 
        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
@@ -129,7 +129,7 @@ xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
                return xpBiosError;
        }
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        u64 nasid_array;
 
        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
@@ -151,9 +151,10 @@ xp_init_uv(void)
        BUG_ON(!is_uv());
 
        xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
+#ifdef CONFIG_X86
        xp_partition_id = sn_partition_id;
        xp_region_size = sn_region_size;
-
+#endif
        xp_pa = xp_pa_uv;
        xp_socket_pa = xp_socket_pa_uv;
        xp_remote_memcpy = xp_remote_memcpy_uv;
index b94d5f7..71db60e 100644 (file)
  *     'SAL_nasids_size'. (Local partition's mask pointers are xpc_part_nasids
  *     and xpc_mach_nasids.)
  *
- *   vars      (ia64-sn2 only)
- *   vars part (ia64-sn2 only)
- *
  *     Immediately following the mach_nasids mask are the XPC variables
  *     required by other partitions. First are those that are generic to all
  *     partitions (vars), followed on the next available cacheline by those
  *     which are partition specific (vars part). These are setup by XPC.
- *     (Local partition's vars pointers are xpc_vars and xpc_vars_part.)
  *
  * Note: Until 'ts_jiffies' is set non-zero, the partition XPC code has not been
  *       initialized.
@@ -92,9 +88,6 @@ struct xpc_rsvd_page {
        u8 pad1[3];             /* align to next u64 in 1st 64-byte cacheline */
        unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */
        union {
-               struct {
-                       unsigned long vars_pa;  /* phys addr */
-               } sn2;
                struct {
                        unsigned long heartbeat_gpa; /* phys addr */
                        unsigned long activate_gru_mq_desc_gpa; /* phys addr */
@@ -106,84 +99,14 @@ struct xpc_rsvd_page {
 
 #define XPC_RP_VERSION _XPC_VERSION(3, 0) /* version 3.0 of the reserved page */
 
-/*
- * Define the structures by which XPC variables can be exported to other
- * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
- */
-
-/*
- * The following structure describes the partition generic variables
- * needed by other partitions in order to properly initialize.
- *
- * struct xpc_vars version number also applies to struct xpc_vars_part.
- * Changes to either structure and/or related functionality should be
- * reflected by incrementing either the major or minor version numbers
- * of struct xpc_vars.
- */
-struct xpc_vars_sn2 {
-       u8 version;
-       u64 heartbeat;
-       DECLARE_BITMAP(heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2);
-       u64 heartbeat_offline;  /* if 0, heartbeat should be changing */
-       int activate_IRQ_nasid;
-       int activate_IRQ_phys_cpuid;
-       unsigned long vars_part_pa;
-       unsigned long amos_page_pa;/* paddr of page of amos from MSPEC driver */
-       struct amo *amos_page;  /* vaddr of page of amos from MSPEC driver */
-};
-
-#define XPC_V_VERSION _XPC_VERSION(3, 1)    /* version 3.1 of the cross vars */
-
-/*
- * The following structure describes the per partition specific variables.
- *
- * An array of these structures, one per partition, will be defined. As a
- * partition becomes active XPC will copy the array entry corresponding to
- * itself from that partition. It is desirable that the size of this structure
- * evenly divides into a 128-byte cacheline, such that none of the entries in
- * this array crosses a 128-byte cacheline boundary. As it is now, each entry
- * occupies 64-bytes.
- */
-struct xpc_vars_part_sn2 {
-       u64 magic;
-
-       unsigned long openclose_args_pa; /* phys addr of open and close args */
-       unsigned long GPs_pa;   /* physical address of Get/Put values */
-
-       unsigned long chctl_amo_pa; /* physical address of chctl flags' amo */
-
-       int notify_IRQ_nasid;   /* nasid of where to send notify IRQs */
-       int notify_IRQ_phys_cpuid;      /* CPUID of where to send notify IRQs */
-
-       u8 nchannels;           /* #of defined channels supported */
-
-       u8 reserved[23];        /* pad to a full 64 bytes */
-};
-
-/*
- * The vars_part MAGIC numbers play a part in the first contact protocol.
- *
- * MAGIC1 indicates that the per partition specific variables for a remote
- * partition have been initialized by this partition.
- *
- * MAGIC2 indicates that this partition has pulled the remote partititions
- * per partition variables that pertain to this partition.
- */
-#define XPC_VP_MAGIC1_SN2 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */
-#define XPC_VP_MAGIC2_SN2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */
-
 /* the reserved page sizes and offsets */
 
 #define XPC_RP_HEADER_SIZE     L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
-#define XPC_RP_VARS_SIZE       L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2))
 
 #define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \
                                 XPC_RP_HEADER_SIZE))
 #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \
                                 xpc_nasid_mask_nlongs)
-#define XPC_RP_VARS(_rp)       ((struct xpc_vars_sn2 *) \
-                                (XPC_RP_MACH_NASIDS(_rp) + \
-                                 xpc_nasid_mask_nlongs))
 
 
 /*
@@ -297,17 +220,6 @@ struct xpc_activate_mq_msg_chctl_opencomplete_uv {
 #define XPC_UNPACK_ARG1(_args) (((u64)_args) & 0xffffffff)
 #define XPC_UNPACK_ARG2(_args) ((((u64)_args) >> 32) & 0xffffffff)
 
-/*
- * Define a Get/Put value pair (pointers) used with a message queue.
- */
-struct xpc_gp_sn2 {
-       s64 get;                /* Get value */
-       s64 put;                /* Put value */
-};
-
-#define XPC_GP_SIZE \
-               L1_CACHE_ALIGN(sizeof(struct xpc_gp_sn2) * XPC_MAX_NCHANNELS)
-
 /*
  * Define a structure that contains arguments associated with opening and
  * closing a channel.
@@ -340,30 +252,6 @@ struct xpc_fifo_head_uv {
        int n_entries;
 };
 
-/*
- * Define a sn2 styled message.
- *
- * A user-defined message resides in the payload area. The max size of the
- * payload is defined by the user via xpc_connect().
- *
- * The size of a message entry (within a message queue) must be a 128-byte
- * cacheline sized multiple in order to facilitate the BTE transfer of messages
- * from one message queue to another.
- */
-struct xpc_msg_sn2 {
-       u8 flags;               /* FOR XPC INTERNAL USE ONLY */
-       u8 reserved[7];         /* FOR XPC INTERNAL USE ONLY */
-       s64 number;             /* FOR XPC INTERNAL USE ONLY */
-
-       u64 payload;            /* user defined portion of message */
-};
-
-/* struct xpc_msg_sn2 flags */
-
-#define        XPC_M_SN2_DONE          0x01    /* msg has been received/consumed */
-#define        XPC_M_SN2_READY         0x02    /* msg is ready to be sent */
-#define        XPC_M_SN2_INTERRUPT     0x04    /* send interrupt when msg consumed */
-
 /*
  * The format of a uv XPC notify_mq GRU message is as follows:
  *
@@ -390,20 +278,6 @@ struct xpc_notify_mq_msg_uv {
        unsigned long payload;
 };
 
-/*
- * Define sn2's notify entry.
- *
- * This is used to notify a message's sender that their message was received
- * and consumed by the intended recipient.
- */
-struct xpc_notify_sn2 {
-       u8 type;                /* type of notification */
-
-       /* the following two fields are only used if type == XPC_N_CALL */
-       xpc_notify_func func;   /* user's notify function */
-       void *key;              /* pointer to user's key */
-};
-
 /* struct xpc_notify_sn2 type of notification */
 
 #define        XPC_N_CALL      0x01    /* notify function provided by user */
@@ -431,102 +305,6 @@ struct xpc_send_msg_slot_uv {
  * of these structures for each potential channel connection to that partition.
  */
 
-/*
- * The following is sn2 only.
- *
- * Each channel structure manages two message queues (circular buffers).
- * They are allocated at the time a channel connection is made. One of
- * these message queues (local_msgqueue) holds the locally created messages
- * that are destined for the remote partition. The other of these message
- * queues (remote_msgqueue) is a locally cached copy of the remote partition's
- * own local_msgqueue.
- *
- * The following is a description of the Get/Put pointers used to manage these
- * two message queues. Consider the local_msgqueue to be on one partition
- * and the remote_msgqueue to be its cached copy on another partition. A
- * description of what each of the lettered areas contains is included.
- *
- *
- *                     local_msgqueue      remote_msgqueue
- *
- *                        |/////////|      |/////////|
- *    w_remote_GP.get --> +---------+      |/////////|
- *                        |    F    |      |/////////|
- *     remote_GP.get  --> +---------+      +---------+ <-- local_GP->get
- *                        |         |      |         |
- *                        |         |      |    E    |
- *                        |         |      |         |
- *                        |         |      +---------+ <-- w_local_GP.get
- *                        |    B    |      |/////////|
- *                        |         |      |////D////|
- *                        |         |      |/////////|
- *                        |         |      +---------+ <-- w_remote_GP.put
- *                        |         |      |////C////|
- *      local_GP->put --> +---------+      +---------+ <-- remote_GP.put
- *                        |         |      |/////////|
- *                        |    A    |      |/////////|
- *                        |         |      |/////////|
- *     w_local_GP.put --> +---------+      |/////////|
- *                        |/////////|      |/////////|
- *
- *
- *         ( remote_GP.[get|put] are cached copies of the remote
- *           partition's local_GP->[get|put], and thus their values can
- *           lag behind their counterparts on the remote partition. )
- *
- *
- *  A - Messages that have been allocated, but have not yet been sent to the
- *     remote partition.
- *
- *  B - Messages that have been sent, but have not yet been acknowledged by the
- *      remote partition as having been received.
- *
- *  C - Area that needs to be prepared for the copying of sent messages, by
- *     the clearing of the message flags of any previously received messages.
- *
- *  D - Area into which sent messages are to be copied from the remote
- *     partition's local_msgqueue and then delivered to their intended
- *     recipients. [ To allow for a multi-message copy, another pointer
- *     (next_msg_to_pull) has been added to keep track of the next message
- *     number needing to be copied (pulled). It chases after w_remote_GP.put.
- *     Any messages lying between w_local_GP.get and next_msg_to_pull have
- *     been copied and are ready to be delivered. ]
- *
- *  E - Messages that have been copied and delivered, but have not yet been
- *     acknowledged by the recipient as having been received.
- *
- *  F - Messages that have been acknowledged, but XPC has not yet notified the
- *     sender that the message was received by its intended recipient.
- *     This is also an area that needs to be prepared for the allocating of
- *     new messages, by the clearing of the message flags of the acknowledged
- *     messages.
- */
-
-struct xpc_channel_sn2 {
-       struct xpc_openclose_args *local_openclose_args; /* args passed on */
-                                            /* opening or closing of channel */
-
-       void *local_msgqueue_base;      /* base address of kmalloc'd space */
-       struct xpc_msg_sn2 *local_msgqueue;     /* local message queue */
-       void *remote_msgqueue_base;     /* base address of kmalloc'd space */
-       struct xpc_msg_sn2 *remote_msgqueue; /* cached copy of remote */
-                                          /* partition's local message queue */
-       unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
-                                         /* local message queue */
-
-       struct xpc_notify_sn2 *notify_queue;/* notify queue for messages sent */
-
-       /* various flavors of local and remote Get/Put values */
-
-       struct xpc_gp_sn2 *local_GP;    /* local Get/Put values */
-       struct xpc_gp_sn2 remote_GP;    /* remote Get/Put values */
-       struct xpc_gp_sn2 w_local_GP;   /* working local Get/Put values */
-       struct xpc_gp_sn2 w_remote_GP;  /* working remote Get/Put values */
-       s64 next_msg_to_pull;   /* Put value of next msg to pull */
-
-       struct mutex msg_to_pull_mutex; /* next msg to pull serialization */
-};
-
 struct xpc_channel_uv {
        void *cached_notify_gru_mq_desc; /* remote partition's notify mq's */
                                         /* gru mq descriptor */
@@ -579,7 +357,6 @@ struct xpc_channel {
        wait_queue_head_t idle_wq;      /* idle kthread wait queue */
 
        union {
-               struct xpc_channel_sn2 sn2;
                struct xpc_channel_uv uv;
        } sn;
 
@@ -666,43 +443,6 @@ xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl)
        return 0;
 }
 
-/*
- * Manage channels on a partition basis. There is one of these structures
- * for each partition (a partition will never utilize the structure that
- * represents itself).
- */
-
-struct xpc_partition_sn2 {
-       unsigned long remote_amos_page_pa; /* paddr of partition's amos page */
-       int activate_IRQ_nasid; /* active partition's act/deact nasid */
-       int activate_IRQ_phys_cpuid;    /* active part's act/deact phys cpuid */
-
-       unsigned long remote_vars_pa;   /* phys addr of partition's vars */
-       unsigned long remote_vars_part_pa; /* paddr of partition's vars part */
-       u8 remote_vars_version; /* version# of partition's vars */
-
-       void *local_GPs_base;   /* base address of kmalloc'd space */
-       struct xpc_gp_sn2 *local_GPs;   /* local Get/Put values */
-       void *remote_GPs_base;  /* base address of kmalloc'd space */
-       struct xpc_gp_sn2 *remote_GPs;  /* copy of remote partition's local */
-                                       /* Get/Put values */
-       unsigned long remote_GPs_pa; /* phys addr of remote partition's local */
-                                    /* Get/Put values */
-
-       void *local_openclose_args_base;   /* base address of kmalloc'd space */
-       struct xpc_openclose_args *local_openclose_args;      /* local's args */
-       unsigned long remote_openclose_args_pa; /* phys addr of remote's args */
-
-       int notify_IRQ_nasid;   /* nasid of where to send notify IRQs */
-       int notify_IRQ_phys_cpuid;      /* CPUID of where to send notify IRQs */
-       char notify_IRQ_owner[8];       /* notify IRQ's owner's name */
-
-       struct amo *remote_chctl_amo_va; /* addr of remote chctl flags' amo */
-       struct amo *local_chctl_amo_va; /* address of chctl flags' amo */
-
-       struct timer_list dropped_notify_IRQ_timer;     /* dropped IRQ timer */
-};
-
 struct xpc_partition_uv {
        unsigned long heartbeat_gpa; /* phys addr of partition's heartbeat */
        struct xpc_heartbeat_uv cached_heartbeat; /* cached copy of */
@@ -774,7 +514,6 @@ struct xpc_partition {
        wait_queue_head_t channel_mgr_wq;       /* channel mgr's wait queue */
 
        union {
-               struct xpc_partition_sn2 sn2;
                struct xpc_partition_uv uv;
        } sn;
 
@@ -854,14 +593,6 @@ struct xpc_arch_operations {
 #define XPC_P_SS_WTEARDOWN     0x02    /* waiting to teardown infrastructure */
 #define XPC_P_SS_TORNDOWN      0x03    /* infrastructure is torndown */
 
-/*
- * struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the
- * following interval #of seconds before checking for dropped notify IRQs.
- * These can occur whenever an IRQ's associated amo write doesn't complete
- * until after the IRQ was received.
- */
-#define XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL   (0.25 * HZ)
-
 /* number of seconds to wait for other partitions to disengage */
 #define XPC_DISENGAGE_DEFAULT_TIMELIMIT                90
 
@@ -888,10 +619,6 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int);
 extern void xpc_create_kthreads(struct xpc_channel *, int, int);
 extern void xpc_disconnect_wait(int);
 
-/* found in xpc_sn2.c */
-extern int xpc_init_sn2(void);
-extern void xpc_exit_sn2(void);
-
 /* found in xpc_uv.c */
 extern int xpc_init_uv(void);
 extern void xpc_exit_uv(void);
index 83fc748..79a9631 100644 (file)
@@ -279,13 +279,6 @@ xpc_hb_checker(void *ignore)
 
                        dev_dbg(xpc_part, "checking remote heartbeats\n");
                        xpc_check_remote_hb();
-
-                       /*
-                        * On sn2 we need to periodically recheck to ensure no
-                        * IRQ/amo pairs have been missed.
-                        */
-                       if (is_shub())
-                               force_IRQ = 1;
                }
 
                /* check for outstanding IRQs */
@@ -1050,9 +1043,7 @@ xpc_do_exit(enum xp_retval reason)
 
        xpc_teardown_partitions();
 
-       if (is_shub())
-               xpc_exit_sn2();
-       else if (is_uv())
+       if (is_uv())
                xpc_exit_uv();
 }
 
@@ -1235,21 +1226,7 @@ xpc_init(void)
        dev_set_name(xpc_part, "part");
        dev_set_name(xpc_chan, "chan");
 
-       if (is_shub()) {
-               /*
-                * The ia64-sn2 architecture supports at most 64 partitions.
-                * And the inability to unregister remote amos restricts us
-                * further to only support exactly 64 partitions on this
-                * architecture, no less.
-                */
-               if (xp_max_npartitions != 64) {
-                       dev_err(xpc_part, "max #of partitions not set to 64\n");
-                       ret = -EINVAL;
-               } else {
-                       ret = xpc_init_sn2();
-               }
-
-       } else if (is_uv()) {
+       if (is_uv()) {
                ret = xpc_init_uv();
 
        } else {
@@ -1335,9 +1312,7 @@ out_2:
 
        xpc_teardown_partitions();
 out_1:
-       if (is_shub())
-               xpc_exit_sn2();
-       else if (is_uv())
+       if (is_uv())
                xpc_exit_uv();
        return ret;
 }
index 782ce95..21a04bc 100644 (file)
@@ -93,10 +93,6 @@ xpc_get_rsvd_page_pa(int nasid)
                if (ret != xpNeedMoreInfo)
                        break;
 
-               /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */
-               if (is_shub())
-                       len = L1_CACHE_ALIGN(len);
-
                if (len > buf_len) {
                        kfree(buf_base);
                        buf_len = L1_CACHE_ALIGN(len);
@@ -452,7 +448,6 @@ xpc_discovery(void)
                case 32:
                        max_regions *= 2;
                        region_size = 16;
-                       DBUG_ON(!is_shub2());
                }
        }
 
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c
deleted file mode 100644 (file)
index 0ae69b9..0000000
+++ /dev/null
@@ -1,2459 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * Cross Partition Communication (XPC) sn2-based functions.
- *
- *     Architecture specific implementation of common functions.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <asm/uncached.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/sn_sal.h>
-#include "xpc.h"
-
-/*
- * Define the number of u64s required to represent all the C-brick nasids
- * as a bitmap.  The cross-partition kernel modules deal only with
- * C-brick nasids, thus the need for bitmaps which don't account for
- * odd-numbered (non C-brick) nasids.
- */
-#define XPC_MAX_PHYSNODES_SN2  (MAX_NUMALINK_NODES / 2)
-#define XP_NASID_MASK_BYTES_SN2        ((XPC_MAX_PHYSNODES_SN2 + 7) / 8)
-#define XP_NASID_MASK_WORDS_SN2        ((XPC_MAX_PHYSNODES_SN2 + 63) / 64)
-
-/*
- * Memory for XPC's amo variables is allocated by the MSPEC driver. These
- * pages are located in the lowest granule. The lowest granule uses 4k pages
- * for cached references and an alternate TLB handler to never provide a
- * cacheable mapping for the entire region. This will prevent speculative
- * reading of cached copies of our lines from being issued which will cause
- * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
- * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of
- * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS_SN2) to identify
- * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote
- * partitions (i.e., XPCs) consider themselves currently engaged with the
- * local XPC and 1 amo variable to request partition deactivation.
- */
-#define XPC_NOTIFY_IRQ_AMOS_SN2                0
-#define XPC_ACTIVATE_IRQ_AMOS_SN2      (XPC_NOTIFY_IRQ_AMOS_SN2 + \
-                                        XP_MAX_NPARTITIONS_SN2)
-#define XPC_ENGAGED_PARTITIONS_AMO_SN2 (XPC_ACTIVATE_IRQ_AMOS_SN2 + \
-                                        XP_NASID_MASK_WORDS_SN2)
-#define XPC_DEACTIVATE_REQUEST_AMO_SN2 (XPC_ENGAGED_PARTITIONS_AMO_SN2 + 1)
-
-/*
- * Buffer used to store a local copy of portions of a remote partition's
- * reserved page (either its header and part_nasids mask, or its vars).
- */
-static void *xpc_remote_copy_buffer_base_sn2;
-static char *xpc_remote_copy_buffer_sn2;
-
-static struct xpc_vars_sn2 *xpc_vars_sn2;
-static struct xpc_vars_part_sn2 *xpc_vars_part_sn2;
-
-static int
-xpc_setup_partitions_sn2(void)
-{
-       /* nothing needs to be done */
-       return 0;
-}
-
-static void
-xpc_teardown_partitions_sn2(void)
-{
-       /* nothing needs to be done */
-}
-
-/* SH_IPI_ACCESS shub register value on startup */
-static u64 xpc_sh1_IPI_access_sn2;
-static u64 xpc_sh2_IPI_access0_sn2;
-static u64 xpc_sh2_IPI_access1_sn2;
-static u64 xpc_sh2_IPI_access2_sn2;
-static u64 xpc_sh2_IPI_access3_sn2;
-
-/*
- * Change protections to allow IPI operations.
- */
-static void
-xpc_allow_IPI_ops_sn2(void)
-{
-       int node;
-       int nasid;
-
-       /* !!! The following should get moved into SAL. */
-       if (is_shub2()) {
-               xpc_sh2_IPI_access0_sn2 =
-                   (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0));
-               xpc_sh2_IPI_access1_sn2 =
-                   (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1));
-               xpc_sh2_IPI_access2_sn2 =
-                   (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2));
-               xpc_sh2_IPI_access3_sn2 =
-                   (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3));
-
-               for_each_online_node(node) {
-                       nasid = cnodeid_to_nasid(node);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
-                             -1UL);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
-                             -1UL);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
-                             -1UL);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
-                             -1UL);
-               }
-       } else {
-               xpc_sh1_IPI_access_sn2 =
-                   (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS));
-
-               for_each_online_node(node) {
-                       nasid = cnodeid_to_nasid(node);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
-                             -1UL);
-               }
-       }
-}
-
-/*
- * Restrict protections to disallow IPI operations.
- */
-static void
-xpc_disallow_IPI_ops_sn2(void)
-{
-       int node;
-       int nasid;
-
-       /* !!! The following should get moved into SAL. */
-       if (is_shub2()) {
-               for_each_online_node(node) {
-                       nasid = cnodeid_to_nasid(node);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
-                             xpc_sh2_IPI_access0_sn2);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
-                             xpc_sh2_IPI_access1_sn2);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
-                             xpc_sh2_IPI_access2_sn2);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
-                             xpc_sh2_IPI_access3_sn2);
-               }
-       } else {
-               for_each_online_node(node) {
-                       nasid = cnodeid_to_nasid(node);
-                       HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
-                             xpc_sh1_IPI_access_sn2);
-               }
-       }
-}
-
-/*
- * The following set of functions are used for the sending and receiving of
- * IRQs (also known as IPIs). There are two flavors of IRQs, one that is
- * associated with partition activity (SGI_XPC_ACTIVATE) and the other that
- * is associated with channel activity (SGI_XPC_NOTIFY).
- */
-
-static u64
-xpc_receive_IRQ_amo_sn2(struct amo *amo)
-{
-       return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR);
-}
-
-static enum xp_retval
-xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid,
-                int vector)
-{
-       int ret = 0;
-       unsigned long irq_flags;
-
-       local_irq_save(irq_flags);
-
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag);
-       sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IRQs and amos to it until the heartbeat times out.
-        */
-       ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
-                                                    xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-
-       return (ret == 0) ? xpSuccess : xpPioReadError;
-}
-
-static struct amo *
-xpc_init_IRQ_amo_sn2(int index)
-{
-       struct amo *amo = xpc_vars_sn2->amos_page + index;
-
-       (void)xpc_receive_IRQ_amo_sn2(amo);     /* clear amo variable */
-       return amo;
-}
-
-/*
- * Functions associated with SGI_XPC_ACTIVATE IRQ.
- */
-
-/*
- * Notify the heartbeat check thread that an activate IRQ has been received.
- */
-static irqreturn_t
-xpc_handle_activate_IRQ_sn2(int irq, void *dev_id)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-       xpc_activate_IRQ_rcvd++;
-       spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
-       wake_up_interruptible(&xpc_activate_IRQ_wq);
-       return IRQ_HANDLED;
-}
-
-/*
- * Flag the appropriate amo variable and send an IRQ to the specified node.
- */
-static void
-xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid,
-                         int to_nasid, int to_phys_cpuid)
-{
-       struct amo *amos = (struct amo *)__va(amos_page_pa +
-                                             (XPC_ACTIVATE_IRQ_AMOS_SN2 *
-                                             sizeof(struct amo)));
-
-       (void)xpc_send_IRQ_sn2(&amos[BIT_WORD(from_nasid / 2)],
-                              BIT_MASK(from_nasid / 2), to_nasid,
-                              to_phys_cpuid, SGI_XPC_ACTIVATE);
-}
-
-static void
-xpc_send_local_activate_IRQ_sn2(int from_nasid)
-{
-       unsigned long irq_flags;
-       struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa +
-                                             (XPC_ACTIVATE_IRQ_AMOS_SN2 *
-                                             sizeof(struct amo)));
-
-       /* fake the sending and receipt of an activate IRQ from remote nasid */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable),
-                        FETCHOP_OR, BIT_MASK(from_nasid / 2));
-
-       spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-       xpc_activate_IRQ_rcvd++;
-       spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
-       wake_up_interruptible(&xpc_activate_IRQ_wq);
-}
-
-/*
- * Functions associated with SGI_XPC_NOTIFY IRQ.
- */
-
-/*
- * Check to see if any chctl flags were sent from the specified partition.
- */
-static void
-xpc_check_for_sent_chctl_flags_sn2(struct xpc_partition *part)
-{
-       union xpc_channel_ctl_flags chctl;
-       unsigned long irq_flags;
-
-       chctl.all_flags = xpc_receive_IRQ_amo_sn2(part->sn.sn2.
-                                                 local_chctl_amo_va);
-       if (chctl.all_flags == 0)
-               return;
-
-       spin_lock_irqsave(&part->chctl_lock, irq_flags);
-       part->chctl.all_flags |= chctl.all_flags;
-       spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
-
-       dev_dbg(xpc_chan, "received notify IRQ from partid=%d, chctl.all_flags="
-               "0x%llx\n", XPC_PARTID(part), chctl.all_flags);
-
-       xpc_wakeup_channel_mgr(part);
-}
-
-/*
- * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified
- * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more
- * than one partition, we use an amo structure per partition to indicate
- * whether a partition has sent an IRQ or not.  If it has, then wake up the
- * associated kthread to handle it.
- *
- * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IRQs sent by XPC
- * running on other partitions.
- *
- * Noteworthy Arguments:
- *
- *     irq - Interrupt ReQuest number. NOT USED.
- *
- *     dev_id - partid of IRQ's potential sender.
- */
-static irqreturn_t
-xpc_handle_notify_IRQ_sn2(int irq, void *dev_id)
-{
-       short partid = (short)(u64)dev_id;
-       struct xpc_partition *part = &xpc_partitions[partid];
-
-       DBUG_ON(partid < 0 || partid >= XP_MAX_NPARTITIONS_SN2);
-
-       if (xpc_part_ref(part)) {
-               xpc_check_for_sent_chctl_flags_sn2(part);
-
-               xpc_part_deref(part);
-       }
-       return IRQ_HANDLED;
-}
-
-/*
- * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IRQs on the floor
- * because the write to their associated amo variable completed after the IRQ
- * was received.
- */
-static void
-xpc_check_for_dropped_notify_IRQ_sn2(struct timer_list *t)
-{
-       struct xpc_partition *part =
-               from_timer(part, t, sn.sn2.dropped_notify_IRQ_timer);
-
-       if (xpc_part_ref(part)) {
-               xpc_check_for_sent_chctl_flags_sn2(part);
-
-               t->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
-               add_timer(t);
-               xpc_part_deref(part);
-       }
-}
-
-/*
- * Send a notify IRQ to the remote partition that is associated with the
- * specified channel.
- */
-static void
-xpc_send_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag,
-                       char *chctl_flag_string, unsigned long *irq_flags)
-{
-       struct xpc_partition *part = &xpc_partitions[ch->partid];
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       union xpc_channel_ctl_flags chctl = { 0 };
-       enum xp_retval ret;
-
-       if (likely(part->act_state != XPC_P_AS_DEACTIVATING)) {
-               chctl.flags[ch->number] = chctl_flag;
-               ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va,
-                                      chctl.all_flags,
-                                      part_sn2->notify_IRQ_nasid,
-                                      part_sn2->notify_IRQ_phys_cpuid,
-                                      SGI_XPC_NOTIFY);
-               dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
-                       chctl_flag_string, ch->partid, ch->number, ret);
-               if (unlikely(ret != xpSuccess)) {
-                       if (irq_flags != NULL)
-                               spin_unlock_irqrestore(&ch->lock, *irq_flags);
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-                       if (irq_flags != NULL)
-                               spin_lock_irqsave(&ch->lock, *irq_flags);
-               }
-       }
-}
-
-#define XPC_SEND_NOTIFY_IRQ_SN2(_ch, _ipi_f, _irq_f) \
-               xpc_send_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f, _irq_f)
-
-/*
- * Make it look like the remote partition, which is associated with the
- * specified channel, sent us a notify IRQ. This faked IRQ will be handled
- * by xpc_check_for_dropped_notify_IRQ_sn2().
- */
-static void
-xpc_send_local_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag,
-                             char *chctl_flag_string)
-{
-       struct xpc_partition *part = &xpc_partitions[ch->partid];
-       union xpc_channel_ctl_flags chctl = { 0 };
-
-       chctl.flags[ch->number] = chctl_flag;
-       FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_chctl_amo_va->
-                               variable), FETCHOP_OR, chctl.all_flags);
-       dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
-               chctl_flag_string, ch->partid, ch->number);
-}
-
-#define XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(_ch, _ipi_f) \
-               xpc_send_local_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f)
-
-static void
-xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch,
-                               unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
-       args->reason = ch->reason;
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags);
-}
-
-static void
-xpc_send_chctl_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREPLY, irq_flags);
-}
-
-static void
-xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
-       args->entry_size = ch->entry_size;
-       args->local_nentries = ch->local_nentries;
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags);
-}
-
-static void
-xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
-       args->remote_nentries = ch->remote_nentries;
-       args->local_nentries = ch->local_nentries;
-       args->local_msgqueue_pa = xp_pa(ch->sn.sn2.local_msgqueue);
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags);
-}
-
-static void
-xpc_send_chctl_opencomplete_sn2(struct xpc_channel *ch,
-                               unsigned long *irq_flags)
-{
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENCOMPLETE, irq_flags);
-}
-
-static void
-xpc_send_chctl_msgrequest_sn2(struct xpc_channel *ch)
-{
-       XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST, NULL);
-}
-
-static void
-xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch)
-{
-       XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST);
-}
-
-static enum xp_retval
-xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch,
-                               unsigned long msgqueue_pa)
-{
-       ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa;
-       return xpSuccess;
-}
-
-/*
- * This next set of functions are used to keep track of when a partition is
- * potentially engaged in accessing memory belonging to another partition.
- */
-
-static void
-xpc_indicate_partition_engaged_sn2(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa +
-                                            (XPC_ENGAGED_PARTITIONS_AMO_SN2 *
-                                            sizeof(struct amo)));
-
-       local_irq_save(irq_flags);
-
-       /* set bit corresponding to our partid in remote partition's amo */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
-                        BIT(sn_partition_id));
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IRQs and amos to it until the heartbeat times out.
-        */
-       (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                                                              variable),
-                                                    xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static void
-xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       unsigned long irq_flags;
-       struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa +
-                                            (XPC_ENGAGED_PARTITIONS_AMO_SN2 *
-                                            sizeof(struct amo)));
-
-       local_irq_save(irq_flags);
-
-       /* clear bit corresponding to our partid in remote partition's amo */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
-                        ~BIT(sn_partition_id));
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IRQs and amos to it until the heartbeat times out.
-        */
-       (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                                                              variable),
-                                                    xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-
-       /*
-        * Send activate IRQ to get other side to see that we've cleared our
-        * bit in their engaged partitions amo.
-        */
-       xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
-                                 cnodeid_to_nasid(0),
-                                 part_sn2->activate_IRQ_nasid,
-                                 part_sn2->activate_IRQ_phys_cpuid);
-}
-
-static void
-xpc_assume_partition_disengaged_sn2(short partid)
-{
-       struct amo *amo = xpc_vars_sn2->amos_page +
-                         XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
-       /* clear bit(s) based on partid mask in our partition's amo */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
-                        ~BIT(partid));
-}
-
-static int
-xpc_partition_engaged_sn2(short partid)
-{
-       struct amo *amo = xpc_vars_sn2->amos_page +
-                         XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
-       /* our partition's amo variable ANDed with partid mask */
-       return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
-               BIT(partid)) != 0;
-}
-
-static int
-xpc_any_partition_engaged_sn2(void)
-{
-       struct amo *amo = xpc_vars_sn2->amos_page +
-                         XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
-       /* our partition's amo variable */
-       return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0;
-}
-
-/* original protection values for each node */
-static u64 xpc_prot_vec_sn2[MAX_NUMNODES];
-
-/*
- * Change protections to allow amo operations on non-Shub 1.1 systems.
- */
-static enum xp_retval
-xpc_allow_amo_ops_sn2(struct amo *amos_page)
-{
-       enum xp_retval ret = xpSuccess;
-
-       /*
-        * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST
-        * collides with memory operations. On those systems we call
-        * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead.
-        */
-       if (!enable_shub_wars_1_1())
-               ret = xp_expand_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE);
-
-       return ret;
-}
-
-/*
- * Change protections to allow amo operations on Shub 1.1 systems.
- */
-static void
-xpc_allow_amo_ops_shub_wars_1_1_sn2(void)
-{
-       int node;
-       int nasid;
-
-       if (!enable_shub_wars_1_1())
-               return;
-
-       for_each_online_node(node) {
-               nasid = cnodeid_to_nasid(node);
-               /* save current protection values */
-               xpc_prot_vec_sn2[node] =
-                   (u64)HUB_L((u64 *)GLOBAL_MMR_ADDR(nasid,
-                                                 SH1_MD_DQLP_MMR_DIR_PRIVEC0));
-               /* open up everything */
-               HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid,
-                                            SH1_MD_DQLP_MMR_DIR_PRIVEC0),
-                     -1UL);
-               HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid,
-                                            SH1_MD_DQRP_MMR_DIR_PRIVEC0),
-                     -1UL);
-       }
-}
-
-static enum xp_retval
-xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa,
-                                  size_t *len)
-{
-       s64 status;
-       enum xp_retval ret;
-
-       status = sn_partition_reserved_page_pa((u64)buf, cookie,
-                       (u64 *)rp_pa, (u64 *)len);
-       if (status == SALRET_OK)
-               ret = xpSuccess;
-       else if (status == SALRET_MORE_PASSES)
-               ret = xpNeedMoreInfo;
-       else
-               ret = xpSalError;
-
-       return ret;
-}
-
-
-static int
-xpc_setup_rsvd_page_sn2(struct xpc_rsvd_page *rp)
-{
-       struct amo *amos_page;
-       int i;
-       int ret;
-
-       xpc_vars_sn2 = XPC_RP_VARS(rp);
-
-       rp->sn.sn2.vars_pa = xp_pa(xpc_vars_sn2);
-
-       /* vars_part array follows immediately after vars */
-       xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) +
-                                                        XPC_RP_VARS_SIZE);
-
-       /*
-        * Before clearing xpc_vars_sn2, see if a page of amos had been
-        * previously allocated. If not we'll need to allocate one and set
-        * permissions so that cross-partition amos are allowed.
-        *
-        * The allocated amo page needs MCA reporting to remain disabled after
-        * XPC has unloaded.  To make this work, we keep a copy of the pointer
-        * to this page (i.e., amos_page) in the struct xpc_vars_sn2 structure,
-        * which is pointed to by the reserved page, and re-use that saved copy
-        * on subsequent loads of XPC. This amo page is never freed, and its
-        * memory protections are never restricted.
-        */
-       amos_page = xpc_vars_sn2->amos_page;
-       if (amos_page == NULL) {
-               amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1));
-               if (amos_page == NULL) {
-                       dev_err(xpc_part, "can't allocate page of amos\n");
-                       return -ENOMEM;
-               }
-
-               /*
-                * Open up amo-R/W to cpu.  This is done on Shub 1.1 systems
-                * when xpc_allow_amo_ops_shub_wars_1_1_sn2() is called.
-                */
-               ret = xpc_allow_amo_ops_sn2(amos_page);
-               if (ret != xpSuccess) {
-                       dev_err(xpc_part, "can't allow amo operations\n");
-                       uncached_free_page(__IA64_UNCACHED_OFFSET |
-                                          TO_PHYS((u64)amos_page), 1);
-                       return -EPERM;
-               }
-       }
-
-       /* clear xpc_vars_sn2 */
-       memset(xpc_vars_sn2, 0, sizeof(struct xpc_vars_sn2));
-
-       xpc_vars_sn2->version = XPC_V_VERSION;
-       xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0);
-       xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0);
-       xpc_vars_sn2->vars_part_pa = xp_pa(xpc_vars_part_sn2);
-       xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page);
-       xpc_vars_sn2->amos_page = amos_page;    /* save for next load of XPC */
-
-       /* clear xpc_vars_part_sn2 */
-       memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) *
-              XP_MAX_NPARTITIONS_SN2);
-
-       /* initialize the activate IRQ related amo variables */
-       for (i = 0; i < xpc_nasid_mask_nlongs; i++)
-               (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS_SN2 + i);
-
-       /* initialize the engaged remote partitions related amo variables */
-       (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2);
-       (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2);
-
-       return 0;
-}
-
-static int
-xpc_hb_allowed_sn2(short partid, void *heartbeating_to_mask)
-{
-       return test_bit(partid, heartbeating_to_mask);
-}
-
-static void
-xpc_allow_hb_sn2(short partid)
-{
-       DBUG_ON(xpc_vars_sn2 == NULL);
-       set_bit(partid, xpc_vars_sn2->heartbeating_to_mask);
-}
-
-static void
-xpc_disallow_hb_sn2(short partid)
-{
-       DBUG_ON(xpc_vars_sn2 == NULL);
-       clear_bit(partid, xpc_vars_sn2->heartbeating_to_mask);
-}
-
-static void
-xpc_disallow_all_hbs_sn2(void)
-{
-       DBUG_ON(xpc_vars_sn2 == NULL);
-       bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, xp_max_npartitions);
-}
-
-static void
-xpc_increment_heartbeat_sn2(void)
-{
-       xpc_vars_sn2->heartbeat++;
-}
-
-static void
-xpc_offline_heartbeat_sn2(void)
-{
-       xpc_increment_heartbeat_sn2();
-       xpc_vars_sn2->heartbeat_offline = 1;
-}
-
-static void
-xpc_online_heartbeat_sn2(void)
-{
-       xpc_increment_heartbeat_sn2();
-       xpc_vars_sn2->heartbeat_offline = 0;
-}
-
-static void
-xpc_heartbeat_init_sn2(void)
-{
-       DBUG_ON(xpc_vars_sn2 == NULL);
-
-       bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2);
-       xpc_online_heartbeat_sn2();
-}
-
-static void
-xpc_heartbeat_exit_sn2(void)
-{
-       xpc_offline_heartbeat_sn2();
-}
-
-static enum xp_retval
-xpc_get_remote_heartbeat_sn2(struct xpc_partition *part)
-{
-       struct xpc_vars_sn2 *remote_vars;
-       enum xp_retval ret;
-
-       remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;
-
-       /* pull the remote vars structure that contains the heartbeat */
-       ret = xp_remote_memcpy(xp_pa(remote_vars),
-                              part->sn.sn2.remote_vars_pa,
-                              XPC_RP_VARS_SIZE);
-       if (ret != xpSuccess)
-               return ret;
-
-       dev_dbg(xpc_part, "partid=%d, heartbeat=%lld, last_heartbeat=%lld, "
-               "heartbeat_offline=%lld, HB_mask[0]=0x%lx\n", XPC_PARTID(part),
-               remote_vars->heartbeat, part->last_heartbeat,
-               remote_vars->heartbeat_offline,
-               remote_vars->heartbeating_to_mask[0]);
-
-       if ((remote_vars->heartbeat == part->last_heartbeat &&
-           !remote_vars->heartbeat_offline) ||
-           !xpc_hb_allowed_sn2(sn_partition_id,
-                               remote_vars->heartbeating_to_mask)) {
-               ret = xpNoHeartbeat;
-       } else {
-               part->last_heartbeat = remote_vars->heartbeat;
-       }
-
-       return ret;
-}
-
-/*
- * Get a copy of the remote partition's XPC variables from the reserved page.
- *
- * remote_vars points to a buffer that is cacheline aligned for BTE copies and
- * assumed to be of size XPC_RP_VARS_SIZE.
- */
-static enum xp_retval
-xpc_get_remote_vars_sn2(unsigned long remote_vars_pa,
-                       struct xpc_vars_sn2 *remote_vars)
-{
-       enum xp_retval ret;
-
-       if (remote_vars_pa == 0)
-               return xpVarsNotSet;
-
-       /* pull over the cross partition variables */
-       ret = xp_remote_memcpy(xp_pa(remote_vars), remote_vars_pa,
-                              XPC_RP_VARS_SIZE);
-       if (ret != xpSuccess)
-               return ret;
-
-       if (XPC_VERSION_MAJOR(remote_vars->version) !=
-           XPC_VERSION_MAJOR(XPC_V_VERSION)) {
-               return xpBadVersion;
-       }
-
-       return xpSuccess;
-}
-
-static void
-xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp,
-                                    unsigned long remote_rp_pa, int nasid)
-{
-       xpc_send_local_activate_IRQ_sn2(nasid);
-}
-
-static void
-xpc_request_partition_reactivation_sn2(struct xpc_partition *part)
-{
-       xpc_send_local_activate_IRQ_sn2(part->sn.sn2.activate_IRQ_nasid);
-}
-
-static void
-xpc_request_partition_deactivation_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       unsigned long irq_flags;
-       struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa +
-                                            (XPC_DEACTIVATE_REQUEST_AMO_SN2 *
-                                            sizeof(struct amo)));
-
-       local_irq_save(irq_flags);
-
-       /* set bit corresponding to our partid in remote partition's amo */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
-                        BIT(sn_partition_id));
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IRQs and amos to it until the heartbeat times out.
-        */
-       (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                                                              variable),
-                                                    xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-
-       /*
-        * Send activate IRQ to get other side to see that we've set our
-        * bit in their deactivate request amo.
-        */
-       xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
-                                 cnodeid_to_nasid(0),
-                                 part_sn2->activate_IRQ_nasid,
-                                 part_sn2->activate_IRQ_phys_cpuid);
-}
-
-static void
-xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa +
-                                            (XPC_DEACTIVATE_REQUEST_AMO_SN2 *
-                                            sizeof(struct amo)));
-
-       local_irq_save(irq_flags);
-
-       /* clear bit corresponding to our partid in remote partition's amo */
-       FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
-                        ~BIT(sn_partition_id));
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IRQs and amos to it until the heartbeat times out.
-        */
-       (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                                                              variable),
-                                                    xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static int
-xpc_partition_deactivation_requested_sn2(short partid)
-{
-       struct amo *amo = xpc_vars_sn2->amos_page +
-                         XPC_DEACTIVATE_REQUEST_AMO_SN2;
-
-       /* our partition's amo variable ANDed with partid mask */
-       return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
-               BIT(partid)) != 0;
-}
-
-/*
- * Update the remote partition's info.
- */
-static void
-xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version,
-                             unsigned long *remote_rp_ts_jiffies,
-                             unsigned long remote_rp_pa,
-                             unsigned long remote_vars_pa,
-                             struct xpc_vars_sn2 *remote_vars)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-
-       part->remote_rp_version = remote_rp_version;
-       dev_dbg(xpc_part, "  remote_rp_version = 0x%016x\n",
-               part->remote_rp_version);
-
-       part->remote_rp_ts_jiffies = *remote_rp_ts_jiffies;
-       dev_dbg(xpc_part, "  remote_rp_ts_jiffies = 0x%016lx\n",
-               part->remote_rp_ts_jiffies);
-
-       part->remote_rp_pa = remote_rp_pa;
-       dev_dbg(xpc_part, "  remote_rp_pa = 0x%016lx\n", part->remote_rp_pa);
-
-       part_sn2->remote_vars_pa = remote_vars_pa;
-       dev_dbg(xpc_part, "  remote_vars_pa = 0x%016lx\n",
-               part_sn2->remote_vars_pa);
-
-       part->last_heartbeat = remote_vars->heartbeat - 1;
-       dev_dbg(xpc_part, "  last_heartbeat = 0x%016llx\n",
-               part->last_heartbeat);
-
-       part_sn2->remote_vars_part_pa = remote_vars->vars_part_pa;
-       dev_dbg(xpc_part, "  remote_vars_part_pa = 0x%016lx\n",
-               part_sn2->remote_vars_part_pa);
-
-       part_sn2->activate_IRQ_nasid = remote_vars->activate_IRQ_nasid;
-       dev_dbg(xpc_part, "  activate_IRQ_nasid = 0x%x\n",
-               part_sn2->activate_IRQ_nasid);
-
-       part_sn2->activate_IRQ_phys_cpuid =
-           remote_vars->activate_IRQ_phys_cpuid;
-       dev_dbg(xpc_part, "  activate_IRQ_phys_cpuid = 0x%x\n",
-               part_sn2->activate_IRQ_phys_cpuid);
-
-       part_sn2->remote_amos_page_pa = remote_vars->amos_page_pa;
-       dev_dbg(xpc_part, "  remote_amos_page_pa = 0x%lx\n",
-               part_sn2->remote_amos_page_pa);
-
-       part_sn2->remote_vars_version = remote_vars->version;
-       dev_dbg(xpc_part, "  remote_vars_version = 0x%x\n",
-               part_sn2->remote_vars_version);
-}
-
-/*
- * Prior code has determined the nasid which generated a activate IRQ.
- * Inspect that nasid to determine if its partition needs to be activated
- * or deactivated.
- *
- * A partition is considered "awaiting activation" if our partition
- * flags indicate it is not active and it has a heartbeat.  A
- * partition is considered "awaiting deactivation" if our partition
- * flags indicate it is active but it has no heartbeat or it is not
- * sending its heartbeat to us.
- *
- * To determine the heartbeat, the remote nasid must have a properly
- * initialized reserved page.
- */
-static void
-xpc_identify_activate_IRQ_req_sn2(int nasid)
-{
-       struct xpc_rsvd_page *remote_rp;
-       struct xpc_vars_sn2 *remote_vars;
-       unsigned long remote_rp_pa;
-       unsigned long remote_vars_pa;
-       int remote_rp_version;
-       int reactivate = 0;
-       unsigned long remote_rp_ts_jiffies = 0;
-       short partid;
-       struct xpc_partition *part;
-       struct xpc_partition_sn2 *part_sn2;
-       enum xp_retval ret;
-
-       /* pull over the reserved page structure */
-
-       remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer_sn2;
-
-       ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa);
-       if (ret != xpSuccess) {
-               dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
-                        "which sent interrupt, reason=%d\n", nasid, ret);
-               return;
-       }
-
-       remote_vars_pa = remote_rp->sn.sn2.vars_pa;
-       remote_rp_version = remote_rp->version;
-       remote_rp_ts_jiffies = remote_rp->ts_jiffies;
-
-       partid = remote_rp->SAL_partid;
-       part = &xpc_partitions[partid];
-       part_sn2 = &part->sn.sn2;
-
-       /* pull over the cross partition variables */
-
-       remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;
-
-       ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars);
-       if (ret != xpSuccess) {
-               dev_warn(xpc_part, "unable to get XPC variables from nasid %d, "
-                        "which sent interrupt, reason=%d\n", nasid, ret);
-
-               XPC_DEACTIVATE_PARTITION(part, ret);
-               return;
-       }
-
-       part->activate_IRQ_rcvd++;
-
-       dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = "
-               "%lld:0x%lx\n", (int)nasid, (int)partid,
-               part->activate_IRQ_rcvd,
-               remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]);
-
-       if (xpc_partition_disengaged(part) &&
-           part->act_state == XPC_P_AS_INACTIVE) {
-
-               xpc_update_partition_info_sn2(part, remote_rp_version,
-                                             &remote_rp_ts_jiffies,
-                                             remote_rp_pa, remote_vars_pa,
-                                             remote_vars);
-
-               if (xpc_partition_deactivation_requested_sn2(partid)) {
-                       /*
-                        * Other side is waiting on us to deactivate even though
-                        * we already have.
-                        */
-                       return;
-               }
-
-               xpc_activate_partition(part);
-               return;
-       }
-
-       DBUG_ON(part->remote_rp_version == 0);
-       DBUG_ON(part_sn2->remote_vars_version == 0);
-
-       if (remote_rp_ts_jiffies != part->remote_rp_ts_jiffies) {
-
-               /* the other side rebooted */
-
-               DBUG_ON(xpc_partition_engaged_sn2(partid));
-               DBUG_ON(xpc_partition_deactivation_requested_sn2(partid));
-
-               xpc_update_partition_info_sn2(part, remote_rp_version,
-                                             &remote_rp_ts_jiffies,
-                                             remote_rp_pa, remote_vars_pa,
-                                             remote_vars);
-               reactivate = 1;
-       }
-
-       if (part->disengage_timeout > 0 && !xpc_partition_disengaged(part)) {
-               /* still waiting on other side to disengage from us */
-               return;
-       }
-
-       if (reactivate)
-               XPC_DEACTIVATE_PARTITION(part, xpReactivating);
-       else if (xpc_partition_deactivation_requested_sn2(partid))
-               XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown);
-}
-
-/*
- * Loop through the activation amo variables and process any bits
- * which are set.  Each bit indicates a nasid sending a partition
- * activation or deactivation request.
- *
- * Return #of IRQs detected.
- */
-int
-xpc_identify_activate_IRQ_sender_sn2(void)
-{
-       int l;
-       int b;
-       unsigned long nasid_mask_long;
-       u64 nasid;              /* remote nasid */
-       int n_IRQs_detected = 0;
-       struct amo *act_amos;
-
-       act_amos = xpc_vars_sn2->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2;
-
-       /* scan through activate amo variables looking for non-zero entries */
-       for (l = 0; l < xpc_nasid_mask_nlongs; l++) {
-
-               if (xpc_exiting)
-                       break;
-
-               nasid_mask_long = xpc_receive_IRQ_amo_sn2(&act_amos[l]);
-
-               b = find_first_bit(&nasid_mask_long, BITS_PER_LONG);
-               if (b >= BITS_PER_LONG) {
-                       /* no IRQs from nasids in this amo variable */
-                       continue;
-               }
-
-               dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", l,
-                       nasid_mask_long);
-
-               /*
-                * If this nasid has been added to the machine since
-                * our partition was reset, this will retain the
-                * remote nasid in our reserved pages machine mask.
-                * This is used in the event of module reload.
-                */
-               xpc_mach_nasids[l] |= nasid_mask_long;
-
-               /* locate the nasid(s) which sent interrupts */
-
-               do {
-                       n_IRQs_detected++;
-                       nasid = (l * BITS_PER_LONG + b) * 2;
-                       dev_dbg(xpc_part, "interrupt from nasid %lld\n", nasid);
-                       xpc_identify_activate_IRQ_req_sn2(nasid);
-
-                       b = find_next_bit(&nasid_mask_long, BITS_PER_LONG,
-                                         b + 1);
-               } while (b < BITS_PER_LONG);
-       }
-       return n_IRQs_detected;
-}
-
-static void
-xpc_process_activate_IRQ_rcvd_sn2(void)
-{
-       unsigned long irq_flags;
-       int n_IRQs_expected;
-       int n_IRQs_detected;
-
-       spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-       n_IRQs_expected = xpc_activate_IRQ_rcvd;
-       xpc_activate_IRQ_rcvd = 0;
-       spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
-       n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2();
-       if (n_IRQs_detected < n_IRQs_expected) {
-               /* retry once to help avoid missing amo */
-               (void)xpc_identify_activate_IRQ_sender_sn2();
-       }
-}
-
-/*
- * Setup the channel structures that are sn2 specific.
- */
-static enum xp_retval
-xpc_setup_ch_structures_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       struct xpc_channel_sn2 *ch_sn2;
-       enum xp_retval retval;
-       int ret;
-       int cpuid;
-       int ch_number;
-       struct timer_list *timer;
-       short partid = XPC_PARTID(part);
-
-       /* allocate all the required GET/PUT values */
-
-       part_sn2->local_GPs =
-           xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
-                                         &part_sn2->local_GPs_base);
-       if (part_sn2->local_GPs == NULL) {
-               dev_err(xpc_chan, "can't get memory for local get/put "
-                       "values\n");
-               return xpNoMemory;
-       }
-
-       part_sn2->remote_GPs =
-           xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
-                                         &part_sn2->remote_GPs_base);
-       if (part_sn2->remote_GPs == NULL) {
-               dev_err(xpc_chan, "can't get memory for remote get/put "
-                       "values\n");
-               retval = xpNoMemory;
-               goto out_1;
-       }
-
-       part_sn2->remote_GPs_pa = 0;
-
-       /* allocate all the required open and close args */
-
-       part_sn2->local_openclose_args =
-           xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE,
-                                         GFP_KERNEL, &part_sn2->
-                                         local_openclose_args_base);
-       if (part_sn2->local_openclose_args == NULL) {
-               dev_err(xpc_chan, "can't get memory for local connect args\n");
-               retval = xpNoMemory;
-               goto out_2;
-       }
-
-       part_sn2->remote_openclose_args_pa = 0;
-
-       part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid);
-
-       part_sn2->notify_IRQ_nasid = 0;
-       part_sn2->notify_IRQ_phys_cpuid = 0;
-       part_sn2->remote_chctl_amo_va = NULL;
-
-       sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid);
-       ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2,
-                         IRQF_SHARED, part_sn2->notify_IRQ_owner,
-                         (void *)(u64)partid);
-       if (ret != 0) {
-               dev_err(xpc_chan, "can't register NOTIFY IRQ handler, "
-                       "errno=%d\n", -ret);
-               retval = xpLackOfResources;
-               goto out_3;
-       }
-
-       /* Setup a timer to check for dropped notify IRQs */
-       timer = &part_sn2->dropped_notify_IRQ_timer;
-       timer_setup(timer, xpc_check_for_dropped_notify_IRQ_sn2, 0);
-       timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
-       add_timer(timer);
-
-       for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
-               ch_sn2 = &part->channels[ch_number].sn.sn2;
-
-               ch_sn2->local_GP = &part_sn2->local_GPs[ch_number];
-               ch_sn2->local_openclose_args =
-                   &part_sn2->local_openclose_args[ch_number];
-
-               mutex_init(&ch_sn2->msg_to_pull_mutex);
-       }
-
-       /*
-        * Setup the per partition specific variables required by the
-        * remote partition to establish channel connections with us.
-        *
-        * The setting of the magic # indicates that these per partition
-        * specific variables are ready to be used.
-        */
-       xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs);
-       xpc_vars_part_sn2[partid].openclose_args_pa =
-           xp_pa(part_sn2->local_openclose_args);
-       xpc_vars_part_sn2[partid].chctl_amo_pa =
-           xp_pa(part_sn2->local_chctl_amo_va);
-       cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */
-       xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid);
-       xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid =
-           cpu_physical_id(cpuid);
-       xpc_vars_part_sn2[partid].nchannels = part->nchannels;
-       xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1_SN2;
-
-       return xpSuccess;
-
-       /* setup of ch structures failed */
-out_3:
-       kfree(part_sn2->local_openclose_args_base);
-       part_sn2->local_openclose_args = NULL;
-out_2:
-       kfree(part_sn2->remote_GPs_base);
-       part_sn2->remote_GPs = NULL;
-out_1:
-       kfree(part_sn2->local_GPs_base);
-       part_sn2->local_GPs = NULL;
-       return retval;
-}
-
-/*
- * Teardown the channel structures that are sn2 specific.
- */
-static void
-xpc_teardown_ch_structures_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       short partid = XPC_PARTID(part);
-
-       /*
-        * Indicate that the variables specific to the remote partition are no
-        * longer available for its use.
-        */
-       xpc_vars_part_sn2[partid].magic = 0;
-
-       /* in case we've still got outstanding timers registered... */
-       del_timer_sync(&part_sn2->dropped_notify_IRQ_timer);
-       free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid);
-
-       kfree(part_sn2->local_openclose_args_base);
-       part_sn2->local_openclose_args = NULL;
-       kfree(part_sn2->remote_GPs_base);
-       part_sn2->remote_GPs = NULL;
-       kfree(part_sn2->local_GPs_base);
-       part_sn2->local_GPs = NULL;
-       part_sn2->local_chctl_amo_va = NULL;
-}
-
-/*
- * Create a wrapper that hides the underlying mechanism for pulling a cacheline
- * (or multiple cachelines) from a remote partition.
- *
- * src_pa must be a cacheline aligned physical address on the remote partition.
- * dst must be a cacheline aligned virtual address on this partition.
- * cnt must be cacheline sized
- */
-/* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */
-static enum xp_retval
-xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst,
-                              const unsigned long src_pa, size_t cnt)
-{
-       enum xp_retval ret;
-
-       DBUG_ON(src_pa != L1_CACHE_ALIGN(src_pa));
-       DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst));
-       DBUG_ON(cnt != L1_CACHE_ALIGN(cnt));
-
-       if (part->act_state == XPC_P_AS_DEACTIVATING)
-               return part->reason;
-
-       ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt);
-       if (ret != xpSuccess) {
-               dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed,"
-                       " ret=%d\n", XPC_PARTID(part), ret);
-       }
-       return ret;
-}
-
-/*
- * Pull the remote per partition specific variables from the specified
- * partition.
- */
-static enum xp_retval
-xpc_pull_remote_vars_part_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       u8 buffer[L1_CACHE_BYTES * 2];
-       struct xpc_vars_part_sn2 *pulled_entry_cacheline =
-           (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer);
-       struct xpc_vars_part_sn2 *pulled_entry;
-       unsigned long remote_entry_cacheline_pa;
-       unsigned long remote_entry_pa;
-       short partid = XPC_PARTID(part);
-       enum xp_retval ret;
-
-       /* pull the cacheline that contains the variables we're interested in */
-
-       DBUG_ON(part_sn2->remote_vars_part_pa !=
-               L1_CACHE_ALIGN(part_sn2->remote_vars_part_pa));
-       DBUG_ON(sizeof(struct xpc_vars_part_sn2) != L1_CACHE_BYTES / 2);
-
-       remote_entry_pa = part_sn2->remote_vars_part_pa +
-           sn_partition_id * sizeof(struct xpc_vars_part_sn2);
-
-       remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1));
-
-       pulled_entry = (struct xpc_vars_part_sn2 *)((u64)pulled_entry_cacheline
-                                                   + (remote_entry_pa &
-                                                   (L1_CACHE_BYTES - 1)));
-
-       ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline,
-                                            remote_entry_cacheline_pa,
-                                            L1_CACHE_BYTES);
-       if (ret != xpSuccess) {
-               dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
-                       "partition %d, ret=%d\n", partid, ret);
-               return ret;
-       }
-
-       /* see if they've been set up yet */
-
-       if (pulled_entry->magic != XPC_VP_MAGIC1_SN2 &&
-           pulled_entry->magic != XPC_VP_MAGIC2_SN2) {
-
-               if (pulled_entry->magic != 0) {
-                       dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
-                               "partition %d has bad magic value (=0x%llx)\n",
-                               partid, sn_partition_id, pulled_entry->magic);
-                       return xpBadMagic;
-               }
-
-               /* they've not been initialized yet */
-               return xpRetry;
-       }
-
-       if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1_SN2) {
-
-               /* validate the variables */
-
-               if (pulled_entry->GPs_pa == 0 ||
-                   pulled_entry->openclose_args_pa == 0 ||
-                   pulled_entry->chctl_amo_pa == 0) {
-
-                       dev_err(xpc_chan, "partition %d's XPC vars_part for "
-                               "partition %d are not valid\n", partid,
-                               sn_partition_id);
-                       return xpInvalidAddress;
-               }
-
-               /* the variables we imported look to be valid */
-
-               part_sn2->remote_GPs_pa = pulled_entry->GPs_pa;
-               part_sn2->remote_openclose_args_pa =
-                   pulled_entry->openclose_args_pa;
-               part_sn2->remote_chctl_amo_va =
-                   (struct amo *)__va(pulled_entry->chctl_amo_pa);
-               part_sn2->notify_IRQ_nasid = pulled_entry->notify_IRQ_nasid;
-               part_sn2->notify_IRQ_phys_cpuid =
-                   pulled_entry->notify_IRQ_phys_cpuid;
-
-               if (part->nchannels > pulled_entry->nchannels)
-                       part->nchannels = pulled_entry->nchannels;
-
-               /* let the other side know that we've pulled their variables */
-
-               xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2_SN2;
-       }
-
-       if (pulled_entry->magic == XPC_VP_MAGIC1_SN2)
-               return xpRetry;
-
-       return xpSuccess;
-}
-
-/*
- * Establish first contact with the remote partititon. This involves pulling
- * the XPC per partition variables from the remote partition and waiting for
- * the remote partition to pull ours.
- */
-static enum xp_retval
-xpc_make_first_contact_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       enum xp_retval ret;
-
-       /*
-        * Register the remote partition's amos with SAL so it can handle
-        * and cleanup errors within that address range should the remote
-        * partition go down. We don't unregister this range because it is
-        * difficult to tell when outstanding writes to the remote partition
-        * are finished and thus when it is safe to unregister. This should
-        * not result in wasted space in the SAL xp_addr_region table because
-        * we should get the same page for remote_amos_page_pa after module
-        * reloads and system reboots.
-        */
-       if (sn_register_xp_addr_region(part_sn2->remote_amos_page_pa,
-                                      PAGE_SIZE, 1) < 0) {
-               dev_warn(xpc_part, "xpc_activating(%d) failed to register "
-                        "xp_addr region\n", XPC_PARTID(part));
-
-               ret = xpPhysAddrRegFailed;
-               XPC_DEACTIVATE_PARTITION(part, ret);
-               return ret;
-       }
-
-       /*
-        * Send activate IRQ to get other side to activate if they've not
-        * already begun to do so.
-        */
-       xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
-                                 cnodeid_to_nasid(0),
-                                 part_sn2->activate_IRQ_nasid,
-                                 part_sn2->activate_IRQ_phys_cpuid);
-
-       while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) {
-               if (ret != xpRetry) {
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-                       return ret;
-               }
-
-               dev_dbg(xpc_part, "waiting to make first contact with "
-                       "partition %d\n", XPC_PARTID(part));
-
-               /* wait a 1/4 of a second or so */
-               (void)msleep_interruptible(250);
-
-               if (part->act_state == XPC_P_AS_DEACTIVATING)
-                       return part->reason;
-       }
-
-       return xpSuccess;
-}
-
-/*
- * Get the chctl flags and pull the openclose args and/or remote GPs as needed.
- */
-static u64
-xpc_get_chctl_all_flags_sn2(struct xpc_partition *part)
-{
-       struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-       unsigned long irq_flags;
-       union xpc_channel_ctl_flags chctl;
-       enum xp_retval ret;
-
-       /*
-        * See if there are any chctl flags to be handled.
-        */
-
-       spin_lock_irqsave(&part->chctl_lock, irq_flags);
-       chctl = part->chctl;
-       if (chctl.all_flags != 0)
-               part->chctl.all_flags = 0;
-
-       spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
-
-       if (xpc_any_openclose_chctl_flags_set(&chctl)) {
-               ret = xpc_pull_remote_cachelines_sn2(part, part->
-                                                    remote_openclose_args,
-                                                    part_sn2->
-                                                    remote_openclose_args_pa,
-                                                    XPC_OPENCLOSE_ARGS_SIZE);
-               if (ret != xpSuccess) {
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-
-                       dev_dbg(xpc_chan, "failed to pull openclose args from "
-                               "partition %d, ret=%d\n", XPC_PARTID(part),
-                               ret);
-
-                       /* don't bother processing chctl flags anymore */
-                       chctl.all_flags = 0;
-               }
-       }
-
-       if (xpc_any_msg_chctl_flags_set(&chctl)) {
-               ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs,
-                                                    part_sn2->remote_GPs_pa,
-                                                    XPC_GP_SIZE);
-               if (ret != xpSuccess) {
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-
-                       dev_dbg(xpc_chan, "failed to pull GPs from partition "
-                               "%d, ret=%d\n", XPC_PARTID(part), ret);
-
-                       /* don't bother processing chctl flags anymore */
-                       chctl.all_flags = 0;
-               }
-       }
-
-       return chctl.all_flags;
-}
-
-/*
- * Allocate the local message queue and the notify queue.
- */
-static enum xp_retval
-xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       unsigned long irq_flags;
-       int nentries;
-       size_t nbytes;
-
-       for (nentries = ch->local_nentries; nentries > 0; nentries--) {
-
-               nbytes = nentries * ch->entry_size;
-               ch_sn2->local_msgqueue =
-                   xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL,
-                                                 &ch_sn2->local_msgqueue_base);
-               if (ch_sn2->local_msgqueue == NULL)
-                       continue;
-
-               nbytes = nentries * sizeof(struct xpc_notify_sn2);
-               ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL);
-               if (ch_sn2->notify_queue == NULL) {
-                       kfree(ch_sn2->local_msgqueue_base);
-                       ch_sn2->local_msgqueue = NULL;
-                       continue;
-               }
-
-               spin_lock_irqsave(&ch->lock, irq_flags);
-               if (nentries < ch->local_nentries) {
-                       dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, "
-                               "partid=%d, channel=%d\n", nentries,
-                               ch->local_nentries, ch->partid, ch->number);
-
-                       ch->local_nentries = nentries;
-               }
-               spin_unlock_irqrestore(&ch->lock, irq_flags);
-               return xpSuccess;
-       }
-
-       dev_dbg(xpc_chan, "can't get memory for local message queue and notify "
-               "queue, partid=%d, channel=%d\n", ch->partid, ch->number);
-       return xpNoMemory;
-}
-
-/*
- * Allocate the cached remote message queue.
- */
-static enum xp_retval
-xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       unsigned long irq_flags;
-       int nentries;
-       size_t nbytes;
-
-       DBUG_ON(ch->remote_nentries <= 0);
-
-       for (nentries = ch->remote_nentries; nentries > 0; nentries--) {
-
-               nbytes = nentries * ch->entry_size;
-               ch_sn2->remote_msgqueue =
-                   xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2->
-                                                 remote_msgqueue_base);
-               if (ch_sn2->remote_msgqueue == NULL)
-                       continue;
-
-               spin_lock_irqsave(&ch->lock, irq_flags);
-               if (nentries < ch->remote_nentries) {
-                       dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, "
-                               "partid=%d, channel=%d\n", nentries,
-                               ch->remote_nentries, ch->partid, ch->number);
-
-                       ch->remote_nentries = nentries;
-               }
-               spin_unlock_irqrestore(&ch->lock, irq_flags);
-               return xpSuccess;
-       }
-
-       dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "
-               "partid=%d, channel=%d\n", ch->partid, ch->number);
-       return xpNoMemory;
-}
-
-/*
- * Allocate message queues and other stuff associated with a channel.
- *
- * Note: Assumes all of the channel sizes are filled in.
- */
-static enum xp_retval
-xpc_setup_msg_structures_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       enum xp_retval ret;
-
-       DBUG_ON(ch->flags & XPC_C_SETUP);
-
-       ret = xpc_allocate_local_msgqueue_sn2(ch);
-       if (ret == xpSuccess) {
-
-               ret = xpc_allocate_remote_msgqueue_sn2(ch);
-               if (ret != xpSuccess) {
-                       kfree(ch_sn2->local_msgqueue_base);
-                       ch_sn2->local_msgqueue = NULL;
-                       kfree(ch_sn2->notify_queue);
-                       ch_sn2->notify_queue = NULL;
-               }
-       }
-       return ret;
-}
-
-/*
- * Free up message queues and other stuff that were allocated for the specified
- * channel.
- */
-static void
-xpc_teardown_msg_structures_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-
-       lockdep_assert_held(&ch->lock);
-
-       ch_sn2->remote_msgqueue_pa = 0;
-
-       ch_sn2->local_GP->get = 0;
-       ch_sn2->local_GP->put = 0;
-       ch_sn2->remote_GP.get = 0;
-       ch_sn2->remote_GP.put = 0;
-       ch_sn2->w_local_GP.get = 0;
-       ch_sn2->w_local_GP.put = 0;
-       ch_sn2->w_remote_GP.get = 0;
-       ch_sn2->w_remote_GP.put = 0;
-       ch_sn2->next_msg_to_pull = 0;
-
-       if (ch->flags & XPC_C_SETUP) {
-               dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n",
-                       ch->flags, ch->partid, ch->number);
-
-               kfree(ch_sn2->local_msgqueue_base);
-               ch_sn2->local_msgqueue = NULL;
-               kfree(ch_sn2->remote_msgqueue_base);
-               ch_sn2->remote_msgqueue = NULL;
-               kfree(ch_sn2->notify_queue);
-               ch_sn2->notify_queue = NULL;
-       }
-}
-
-/*
- * Notify those who wanted to be notified upon delivery of their message.
- */
-static void
-xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put)
-{
-       struct xpc_notify_sn2 *notify;
-       u8 notify_type;
-       s64 get = ch->sn.sn2.w_remote_GP.get - 1;
-
-       while (++get < put && atomic_read(&ch->n_to_notify) > 0) {
-
-               notify = &ch->sn.sn2.notify_queue[get % ch->local_nentries];
-
-               /*
-                * See if the notify entry indicates it was associated with
-                * a message who's sender wants to be notified. It is possible
-                * that it is, but someone else is doing or has done the
-                * notification.
-                */
-               notify_type = notify->type;
-               if (notify_type == 0 ||
-                   cmpxchg(&notify->type, notify_type, 0) != notify_type) {
-                       continue;
-               }
-
-               DBUG_ON(notify_type != XPC_N_CALL);
-
-               atomic_dec(&ch->n_to_notify);
-
-               if (notify->func != NULL) {
-                       dev_dbg(xpc_chan, "notify->func() called, notify=0x%p "
-                               "msg_number=%lld partid=%d channel=%d\n",
-                               (void *)notify, get, ch->partid, ch->number);
-
-                       notify->func(reason, ch->partid, ch->number,
-                                    notify->key);
-
-                       dev_dbg(xpc_chan, "notify->func() returned, notify=0x%p"
-                               " msg_number=%lld partid=%d channel=%d\n",
-                               (void *)notify, get, ch->partid, ch->number);
-               }
-       }
-}
-
-static void
-xpc_notify_senders_of_disconnect_sn2(struct xpc_channel *ch)
-{
-       xpc_notify_senders_sn2(ch, ch->reason, ch->sn.sn2.w_local_GP.put);
-}
-
-/*
- * Clear some of the msg flags in the local message queue.
- */
-static inline void
-xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       s64 get;
-
-       get = ch_sn2->w_remote_GP.get;
-       do {
-               msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
-                                            (get % ch->local_nentries) *
-                                            ch->entry_size);
-               DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
-               msg->flags = 0;
-       } while (++get < ch_sn2->remote_GP.get);
-}
-
-/*
- * Clear some of the msg flags in the remote message queue.
- */
-static inline void
-xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       s64 put, remote_nentries = ch->remote_nentries;
-
-       /* flags are zeroed when the buffer is allocated */
-       if (ch_sn2->remote_GP.put < remote_nentries)
-               return;
-
-       put = max(ch_sn2->w_remote_GP.put, remote_nentries);
-       do {
-               msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
-                                            (put % remote_nentries) *
-                                            ch->entry_size);
-               DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
-               DBUG_ON(!(msg->flags & XPC_M_SN2_DONE));
-               DBUG_ON(msg->number != put - remote_nentries);
-               msg->flags = 0;
-       } while (++put < ch_sn2->remote_GP.put);
-}
-
-static int
-xpc_n_of_deliverable_payloads_sn2(struct xpc_channel *ch)
-{
-       return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get;
-}
-
-static void
-xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number)
-{
-       struct xpc_channel *ch = &part->channels[ch_number];
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       int npayloads_sent;
-
-       ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number];
-
-       /* See what, if anything, has changed for each connected channel */
-
-       xpc_msgqueue_ref(ch);
-
-       if (ch_sn2->w_remote_GP.get == ch_sn2->remote_GP.get &&
-           ch_sn2->w_remote_GP.put == ch_sn2->remote_GP.put) {
-               /* nothing changed since GPs were last pulled */
-               xpc_msgqueue_deref(ch);
-               return;
-       }
-
-       if (!(ch->flags & XPC_C_CONNECTED)) {
-               xpc_msgqueue_deref(ch);
-               return;
-       }
-
-       /*
-        * First check to see if messages recently sent by us have been
-        * received by the other side. (The remote GET value will have
-        * changed since we last looked at it.)
-        */
-
-       if (ch_sn2->w_remote_GP.get != ch_sn2->remote_GP.get) {
-
-               /*
-                * We need to notify any senders that want to be notified
-                * that their sent messages have been received by their
-                * intended recipients. We need to do this before updating
-                * w_remote_GP.get so that we don't allocate the same message
-                * queue entries prematurely (see xpc_allocate_msg()).
-                */
-               if (atomic_read(&ch->n_to_notify) > 0) {
-                       /*
-                        * Notify senders that messages sent have been
-                        * received and delivered by the other side.
-                        */
-                       xpc_notify_senders_sn2(ch, xpMsgDelivered,
-                                              ch_sn2->remote_GP.get);
-               }
-
-               /*
-                * Clear msg->flags in previously sent messages, so that
-                * they're ready for xpc_allocate_msg().
-                */
-               xpc_clear_local_msgqueue_flags_sn2(ch);
-
-               ch_sn2->w_remote_GP.get = ch_sn2->remote_GP.get;
-
-               dev_dbg(xpc_chan, "w_remote_GP.get changed to %lld, partid=%d, "
-                       "channel=%d\n", ch_sn2->w_remote_GP.get, ch->partid,
-                       ch->number);
-
-               /*
-                * If anyone was waiting for message queue entries to become
-                * available, wake them up.
-                */
-               if (atomic_read(&ch->n_on_msg_allocate_wq) > 0)
-                       wake_up(&ch->msg_allocate_wq);
-       }
-
-       /*
-        * Now check for newly sent messages by the other side. (The remote
-        * PUT value will have changed since we last looked at it.)
-        */
-
-       if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) {
-               /*
-                * Clear msg->flags in previously received messages, so that
-                * they're ready for xpc_get_deliverable_payload_sn2().
-                */
-               xpc_clear_remote_msgqueue_flags_sn2(ch);
-
-               smp_wmb(); /* ensure flags have been cleared before bte_copy */
-               ch_sn2->w_remote_GP.put = ch_sn2->remote_GP.put;
-
-               dev_dbg(xpc_chan, "w_remote_GP.put changed to %lld, partid=%d, "
-                       "channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid,
-                       ch->number);
-
-               npayloads_sent = xpc_n_of_deliverable_payloads_sn2(ch);
-               if (npayloads_sent > 0) {
-                       dev_dbg(xpc_chan, "msgs waiting to be copied and "
-                               "delivered=%d, partid=%d, channel=%d\n",
-                               npayloads_sent, ch->partid, ch->number);
-
-                       if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)
-                               xpc_activate_kthreads(ch, npayloads_sent);
-               }
-       }
-
-       xpc_msgqueue_deref(ch);
-}
-
-static struct xpc_msg_sn2 *
-xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get)
-{
-       struct xpc_partition *part = &xpc_partitions[ch->partid];
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       unsigned long remote_msg_pa;
-       struct xpc_msg_sn2 *msg;
-       u32 msg_index;
-       u32 nmsgs;
-       u64 msg_offset;
-       enum xp_retval ret;
-
-       if (mutex_lock_interruptible(&ch_sn2->msg_to_pull_mutex) != 0) {
-               /* we were interrupted by a signal */
-               return NULL;
-       }
-
-       while (get >= ch_sn2->next_msg_to_pull) {
-
-               /* pull as many messages as are ready and able to be pulled */
-
-               msg_index = ch_sn2->next_msg_to_pull % ch->remote_nentries;
-
-               DBUG_ON(ch_sn2->next_msg_to_pull >= ch_sn2->w_remote_GP.put);
-               nmsgs = ch_sn2->w_remote_GP.put - ch_sn2->next_msg_to_pull;
-               if (msg_index + nmsgs > ch->remote_nentries) {
-                       /* ignore the ones that wrap the msg queue for now */
-                       nmsgs = ch->remote_nentries - msg_index;
-               }
-
-               msg_offset = msg_index * ch->entry_size;
-               msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
-                   msg_offset);
-               remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset;
-
-               ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa,
-                                                    nmsgs * ch->entry_size);
-               if (ret != xpSuccess) {
-
-                       dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
-                               " msg %lld from partition %d, channel=%d, "
-                               "ret=%d\n", nmsgs, ch_sn2->next_msg_to_pull,
-                               ch->partid, ch->number, ret);
-
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-
-                       mutex_unlock(&ch_sn2->msg_to_pull_mutex);
-                       return NULL;
-               }
-
-               ch_sn2->next_msg_to_pull += nmsgs;
-       }
-
-       mutex_unlock(&ch_sn2->msg_to_pull_mutex);
-
-       /* return the message we were looking for */
-       msg_offset = (get % ch->remote_nentries) * ch->entry_size;
-       msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset);
-
-       return msg;
-}
-
-/*
- * Get the next deliverable message's payload.
- */
-static void *
-xpc_get_deliverable_payload_sn2(struct xpc_channel *ch)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       void *payload = NULL;
-       s64 get;
-
-       do {
-               if (ch->flags & XPC_C_DISCONNECTING)
-                       break;
-
-               get = ch_sn2->w_local_GP.get;
-               smp_rmb();      /* guarantee that .get loads before .put */
-               if (get == ch_sn2->w_remote_GP.put)
-                       break;
-
-               /* There are messages waiting to be pulled and delivered.
-                * We need to try to secure one for ourselves. We'll do this
-                * by trying to increment w_local_GP.get and hope that no one
-                * else beats us to it. If they do, we'll we'll simply have
-                * to try again for the next one.
-                */
-
-               if (cmpxchg(&ch_sn2->w_local_GP.get, get, get + 1) == get) {
-                       /* we got the entry referenced by get */
-
-                       dev_dbg(xpc_chan, "w_local_GP.get changed to %lld, "
-                               "partid=%d, channel=%d\n", get + 1,
-                               ch->partid, ch->number);
-
-                       /* pull the message from the remote partition */
-
-                       msg = xpc_pull_remote_msg_sn2(ch, get);
-
-                       if (msg != NULL) {
-                               DBUG_ON(msg->number != get);
-                               DBUG_ON(msg->flags & XPC_M_SN2_DONE);
-                               DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
-
-                               payload = &msg->payload;
-                       }
-                       break;
-               }
-
-       } while (1);
-
-       return payload;
-}
-
-/*
- * Now we actually send the messages that are ready to be sent by advancing
- * the local message queue's Put value and then send a chctl msgrequest to the
- * recipient partition.
- */
-static void
-xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       s64 put = initial_put + 1;
-       int send_msgrequest = 0;
-
-       while (1) {
-
-               while (1) {
-                       if (put == ch_sn2->w_local_GP.put)
-                               break;
-
-                       msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
-                                                    local_msgqueue + (put %
-                                                    ch->local_nentries) *
-                                                    ch->entry_size);
-
-                       if (!(msg->flags & XPC_M_SN2_READY))
-                               break;
-
-                       put++;
-               }
-
-               if (put == initial_put) {
-                       /* nothing's changed */
-                       break;
-               }
-
-               if (cmpxchg_rel(&ch_sn2->local_GP->put, initial_put, put) !=
-                   initial_put) {
-                       /* someone else beat us to it */
-                       DBUG_ON(ch_sn2->local_GP->put < initial_put);
-                       break;
-               }
-
-               /* we just set the new value of local_GP->put */
-
-               dev_dbg(xpc_chan, "local_GP->put changed to %lld, partid=%d, "
-                       "channel=%d\n", put, ch->partid, ch->number);
-
-               send_msgrequest = 1;
-
-               /*
-                * We need to ensure that the message referenced by
-                * local_GP->put is not XPC_M_SN2_READY or that local_GP->put
-                * equals w_local_GP.put, so we'll go have a look.
-                */
-               initial_put = put;
-       }
-
-       if (send_msgrequest)
-               xpc_send_chctl_msgrequest_sn2(ch);
-}
-
-/*
- * Allocate an entry for a message from the message queue associated with the
- * specified channel.
- */
-static enum xp_retval
-xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags,
-                    struct xpc_msg_sn2 **address_of_msg)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       enum xp_retval ret;
-       s64 put;
-
-       /*
-        * Get the next available message entry from the local message queue.
-        * If none are available, we'll make sure that we grab the latest
-        * GP values.
-        */
-       ret = xpTimeout;
-
-       while (1) {
-
-               put = ch_sn2->w_local_GP.put;
-               smp_rmb();      /* guarantee that .put loads before .get */
-               if (put - ch_sn2->w_remote_GP.get < ch->local_nentries) {
-
-                       /* There are available message entries. We need to try
-                        * to secure one for ourselves. We'll do this by trying
-                        * to increment w_local_GP.put as long as someone else
-                        * doesn't beat us to it. If they do, we'll have to
-                        * try again.
-                        */
-                       if (cmpxchg(&ch_sn2->w_local_GP.put, put, put + 1) ==
-                           put) {
-                               /* we got the entry referenced by put */
-                               break;
-                       }
-                       continue;       /* try again */
-               }
-
-               /*
-                * There aren't any available msg entries at this time.
-                *
-                * In waiting for a message entry to become available,
-                * we set a timeout in case the other side is not sending
-                * completion interrupts. This lets us fake a notify IRQ
-                * that will cause the notify IRQ handler to fetch the latest
-                * GP values as if an interrupt was sent by the other side.
-                */
-               if (ret == xpTimeout)
-                       xpc_send_chctl_local_msgrequest_sn2(ch);
-
-               if (flags & XPC_NOWAIT)
-                       return xpNoWait;
-
-               ret = xpc_allocate_msg_wait(ch);
-               if (ret != xpInterrupted && ret != xpTimeout)
-                       return ret;
-       }
-
-       /* get the message's address and initialize it */
-       msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
-                                    (put % ch->local_nentries) *
-                                    ch->entry_size);
-
-       DBUG_ON(msg->flags != 0);
-       msg->number = put;
-
-       dev_dbg(xpc_chan, "w_local_GP.put changed to %lld; msg=0x%p, "
-               "msg_number=%lld, partid=%d, channel=%d\n", put + 1,
-               (void *)msg, msg->number, ch->partid, ch->number);
-
-       *address_of_msg = msg;
-       return xpSuccess;
-}
-
-/*
- * Common code that does the actual sending of the message by advancing the
- * local message queue's Put value and sends a chctl msgrequest to the
- * partition the message is being sent to.
- */
-static enum xp_retval
-xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload,
-                    u16 payload_size, u8 notify_type, xpc_notify_func func,
-                    void *key)
-{
-       enum xp_retval ret = xpSuccess;
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg = msg;
-       struct xpc_notify_sn2 *notify = notify;
-       s64 msg_number;
-       s64 put;
-
-       DBUG_ON(notify_type == XPC_N_CALL && func == NULL);
-
-       if (XPC_MSG_SIZE(payload_size) > ch->entry_size)
-               return xpPayloadTooBig;
-
-       xpc_msgqueue_ref(ch);
-
-       if (ch->flags & XPC_C_DISCONNECTING) {
-               ret = ch->reason;
-               goto out_1;
-       }
-       if (!(ch->flags & XPC_C_CONNECTED)) {
-               ret = xpNotConnected;
-               goto out_1;
-       }
-
-       ret = xpc_allocate_msg_sn2(ch, flags, &msg);
-       if (ret != xpSuccess)
-               goto out_1;
-
-       msg_number = msg->number;
-
-       if (notify_type != 0) {
-               /*
-                * Tell the remote side to send an ACK interrupt when the
-                * message has been delivered.
-                */
-               msg->flags |= XPC_M_SN2_INTERRUPT;
-
-               atomic_inc(&ch->n_to_notify);
-
-               notify = &ch_sn2->notify_queue[msg_number % ch->local_nentries];
-               notify->func = func;
-               notify->key = key;
-               notify->type = notify_type;
-
-               /* ??? Is a mb() needed here? */
-
-               if (ch->flags & XPC_C_DISCONNECTING) {
-                       /*
-                        * An error occurred between our last error check and
-                        * this one. We will try to clear the type field from
-                        * the notify entry. If we succeed then
-                        * xpc_disconnect_channel() didn't already process
-                        * the notify entry.
-                        */
-                       if (cmpxchg(&notify->type, notify_type, 0) ==
-                           notify_type) {
-                               atomic_dec(&ch->n_to_notify);
-                               ret = ch->reason;
-                       }
-                       goto out_1;
-               }
-       }
-
-       memcpy(&msg->payload, payload, payload_size);
-
-       msg->flags |= XPC_M_SN2_READY;
-
-       /*
-        * The preceding store of msg->flags must occur before the following
-        * load of local_GP->put.
-        */
-       smp_mb();
-
-       /* see if the message is next in line to be sent, if so send it */
-
-       put = ch_sn2->local_GP->put;
-       if (put == msg_number)
-               xpc_send_msgs_sn2(ch, put);
-
-out_1:
-       xpc_msgqueue_deref(ch);
-       return ret;
-}
-
-/*
- * Now we actually acknowledge the messages that have been delivered and ack'd
- * by advancing the cached remote message queue's Get value and if requested
- * send a chctl msgrequest to the message sender's partition.
- *
- * If a message has XPC_M_SN2_INTERRUPT set, send an interrupt to the partition
- * that sent the message.
- */
-static void
-xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags)
-{
-       struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-       struct xpc_msg_sn2 *msg;
-       s64 get = initial_get + 1;
-       int send_msgrequest = 0;
-
-       while (1) {
-
-               while (1) {
-                       if (get == ch_sn2->w_local_GP.get)
-                               break;
-
-                       msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
-                                                    remote_msgqueue + (get %
-                                                    ch->remote_nentries) *
-                                                    ch->entry_size);
-
-                       if (!(msg->flags & XPC_M_SN2_DONE))
-                               break;
-
-                       msg_flags |= msg->flags;
-                       get++;
-               }
-
-               if (get == initial_get) {
-                       /* nothing's changed */
-                       break;
-               }
-
-               if (cmpxchg_rel(&ch_sn2->local_GP->get, initial_get, get) !=
-                   initial_get) {
-                       /* someone else beat us to it */
-                       DBUG_ON(ch_sn2->local_GP->get <= initial_get);
-                       break;
-               }
-
-               /* we just set the new value of local_GP->get */
-
-               dev_dbg(xpc_chan, "local_GP->get changed to %lld, partid=%d, "
-                       "channel=%d\n", get, ch->partid, ch->number);
-
-               send_msgrequest = (msg_flags & XPC_M_SN2_INTERRUPT);
-
-               /*
-                * We need to ensure that the message referenced by
-                * local_GP->get is not XPC_M_SN2_DONE or that local_GP->get
-                * equals w_local_GP.get, so we'll go have a look.
-                */
-               initial_get = get;
-       }
-
-       if (send_msgrequest)
-               xpc_send_chctl_msgrequest_sn2(ch);
-}
-
-static void
-xpc_received_payload_sn2(struct xpc_channel *ch, void *payload)
-{
-       struct xpc_msg_sn2 *msg;
-       s64 msg_number;
-       s64 get;
-
-       msg = container_of(payload, struct xpc_msg_sn2, payload);
-       msg_number = msg->number;
-
-       dev_dbg(xpc_chan, "msg=0x%p, msg_number=%lld, partid=%d, channel=%d\n",
-               (void *)msg, msg_number, ch->partid, ch->number);
-
-       DBUG_ON((((u64)msg - (u64)ch->sn.sn2.remote_msgqueue) / ch->entry_size) !=
-               msg_number % ch->remote_nentries);
-       DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
-       DBUG_ON(msg->flags & XPC_M_SN2_DONE);
-
-       msg->flags |= XPC_M_SN2_DONE;
-
-       /*
-        * The preceding store of msg->flags must occur before the following
-        * load of local_GP->get.
-        */
-       smp_mb();
-
-       /*
-        * See if this message is next in line to be acknowledged as having
-        * been delivered.
-        */
-       get = ch->sn.sn2.local_GP->get;
-       if (get == msg_number)
-               xpc_acknowledge_msgs_sn2(ch, get, msg->flags);
-}
-
-static struct xpc_arch_operations xpc_arch_ops_sn2 = {
-       .setup_partitions = xpc_setup_partitions_sn2,
-       .teardown_partitions = xpc_teardown_partitions_sn2,
-       .process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2,
-       .get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2,
-       .setup_rsvd_page = xpc_setup_rsvd_page_sn2,
-
-       .allow_hb = xpc_allow_hb_sn2,
-       .disallow_hb = xpc_disallow_hb_sn2,
-       .disallow_all_hbs = xpc_disallow_all_hbs_sn2,
-       .increment_heartbeat = xpc_increment_heartbeat_sn2,
-       .offline_heartbeat = xpc_offline_heartbeat_sn2,
-       .online_heartbeat = xpc_online_heartbeat_sn2,
-       .heartbeat_init = xpc_heartbeat_init_sn2,
-       .heartbeat_exit = xpc_heartbeat_exit_sn2,
-       .get_remote_heartbeat = xpc_get_remote_heartbeat_sn2,
-
-       .request_partition_activation =
-               xpc_request_partition_activation_sn2,
-       .request_partition_reactivation =
-               xpc_request_partition_reactivation_sn2,
-       .request_partition_deactivation =
-               xpc_request_partition_deactivation_sn2,
-       .cancel_partition_deactivation_request =
-               xpc_cancel_partition_deactivation_request_sn2,
-
-       .setup_ch_structures = xpc_setup_ch_structures_sn2,
-       .teardown_ch_structures = xpc_teardown_ch_structures_sn2,
-
-       .make_first_contact = xpc_make_first_contact_sn2,
-
-       .get_chctl_all_flags = xpc_get_chctl_all_flags_sn2,
-       .send_chctl_closerequest = xpc_send_chctl_closerequest_sn2,
-       .send_chctl_closereply = xpc_send_chctl_closereply_sn2,
-       .send_chctl_openrequest = xpc_send_chctl_openrequest_sn2,
-       .send_chctl_openreply = xpc_send_chctl_openreply_sn2,
-       .send_chctl_opencomplete = xpc_send_chctl_opencomplete_sn2,
-       .process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2,
-
-       .save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_sn2,
-
-       .setup_msg_structures = xpc_setup_msg_structures_sn2,
-       .teardown_msg_structures = xpc_teardown_msg_structures_sn2,
-
-       .indicate_partition_engaged = xpc_indicate_partition_engaged_sn2,
-       .indicate_partition_disengaged = xpc_indicate_partition_disengaged_sn2,
-       .partition_engaged = xpc_partition_engaged_sn2,
-       .any_partition_engaged = xpc_any_partition_engaged_sn2,
-       .assume_partition_disengaged = xpc_assume_partition_disengaged_sn2,
-
-       .n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_sn2,
-       .send_payload = xpc_send_payload_sn2,
-       .get_deliverable_payload = xpc_get_deliverable_payload_sn2,
-       .received_payload = xpc_received_payload_sn2,
-       .notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2,
-};
-
-int
-xpc_init_sn2(void)
-{
-       int ret;
-       size_t buf_size;
-
-       xpc_arch_ops = xpc_arch_ops_sn2;
-
-       if (offsetof(struct xpc_msg_sn2, payload) > XPC_MSG_HDR_MAX_SIZE) {
-               dev_err(xpc_part, "header portion of struct xpc_msg_sn2 is "
-                       "larger than %d\n", XPC_MSG_HDR_MAX_SIZE);
-               return -E2BIG;
-       }
-
-       buf_size = max(XPC_RP_VARS_SIZE,
-                      XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2);
-       xpc_remote_copy_buffer_sn2 = xpc_kmalloc_cacheline_aligned(buf_size,
-                                                                  GFP_KERNEL,
-                                             &xpc_remote_copy_buffer_base_sn2);
-       if (xpc_remote_copy_buffer_sn2 == NULL) {
-               dev_err(xpc_part, "can't get memory for remote copy buffer\n");
-               return -ENOMEM;
-       }
-
-       /* open up protections for IPI and [potentially] amo operations */
-       xpc_allow_IPI_ops_sn2();
-       xpc_allow_amo_ops_shub_wars_1_1_sn2();
-
-       /*
-        * This is safe to do before the xpc_hb_checker thread has started
-        * because the handler releases a wait queue.  If an interrupt is
-        * received before the thread is waiting, it will not go to sleep,
-        * but rather immediately process the interrupt.
-        */
-       ret = request_irq(SGI_XPC_ACTIVATE, xpc_handle_activate_IRQ_sn2, 0,
-                         "xpc hb", NULL);
-       if (ret != 0) {
-               dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "
-                       "errno=%d\n", -ret);
-               xpc_disallow_IPI_ops_sn2();
-               kfree(xpc_remote_copy_buffer_base_sn2);
-       }
-       return ret;
-}
-
-void
-xpc_exit_sn2(void)
-{
-       free_irq(SGI_XPC_ACTIVATE, NULL);
-       xpc_disallow_IPI_ops_sn2();
-       kfree(xpc_remote_copy_buffer_base_sn2);
-}
index 0c6de97..09e2465 100644 (file)
@@ -27,7 +27,7 @@
 #if defined CONFIG_X86_64
 #include <asm/uv/bios.h>
 #include <asm/uv/uv_irq.h>
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
 #endif
@@ -35,7 +35,7 @@
 #include "../sgi-gru/grukservices.h"
 #include "xpc.h"
 
-#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#if defined CONFIG_IA64_SGI_UV
 struct uv_IO_APIC_route_entry {
        __u64   vector          :  8,
                delivery_mode   :  3,
@@ -48,6 +48,8 @@ struct uv_IO_APIC_route_entry {
                __reserved_2    : 15,
                dest            : 32;
 };
+
+#define sn_partition_id 0
 #endif
 
 static struct xpc_heartbeat_uv *xpc_heartbeat_uv;
@@ -119,7 +121,7 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
 
        mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
                mq->irq = SGI_XPC_ACTIVATE;
        else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
@@ -142,7 +144,7 @@ xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
 #if defined CONFIG_X86_64
        uv_teardown_irq(mq->irq);
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        int mmr_pnode;
        unsigned long mmr_value;
 
@@ -160,7 +162,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
 {
        int ret;
 
-#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#if defined CONFIG_IA64_SGI_UV
        int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
 
        ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address),
@@ -195,7 +197,7 @@ xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq)
 #if defined CONFIG_X86_64
        ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
        BUG_ON(ret != BIOS_STATUS_SUCCESS);
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
        BUG_ON(ret != SALRET_OK);
 #else
@@ -794,7 +796,7 @@ xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
        else
                ret = xpBiosError;
 
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
        status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len);
        if (status == SALRET_OK)
                ret = xpSuccess;
index 44d750d..f7d610a 100644 (file)
@@ -515,7 +515,7 @@ xpnet_init(void)
 {
        int result;
 
-       if (!is_shub() && !is_uv())
+       if (!is_uv())
                return -ENODEV;
 
        dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);
index 8840299..5e6be15 100644 (file)
@@ -691,7 +691,6 @@ static int vmballoon_alloc_page_list(struct vmballoon *b,
                }
 
                if (page) {
-                       vmballoon_mark_page_offline(page, ctl->page_size);
                        /* Success. Add the page to the list and continue. */
                        list_add(&page->lru, &ctl->pages);
                        continue;
@@ -930,7 +929,6 @@ static void vmballoon_release_page_list(struct list_head *page_list,
 
        list_for_each_entry_safe(page, tmp, page_list, lru) {
                list_del(&page->lru);
-               vmballoon_mark_page_online(page, page_size);
                __free_pages(page, vmballoon_page_order(page_size));
        }
 
@@ -1005,6 +1003,7 @@ static void vmballoon_enqueue_page_list(struct vmballoon *b,
                                        enum vmballoon_page_size_type page_size)
 {
        unsigned long flags;
+       struct page *page;
 
        if (page_size == VMW_BALLOON_4K_PAGE) {
                balloon_page_list_enqueue(&b->b_dev_info, pages);
@@ -1014,6 +1013,11 @@ static void vmballoon_enqueue_page_list(struct vmballoon *b,
                 * for the balloon compaction mechanism.
                 */
                spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+
+               list_for_each_entry(page, pages, lru) {
+                       vmballoon_mark_page_offline(page, VMW_BALLOON_2M_PAGE);
+               }
+
                list_splice_init(pages, &b->huge_pages);
                __count_vm_events(BALLOON_INFLATE, *n_pages *
                                  vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE));
@@ -1056,6 +1060,8 @@ static void vmballoon_dequeue_page_list(struct vmballoon *b,
        /* 2MB pages */
        spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
        list_for_each_entry_safe(page, tmp, &b->huge_pages, lru) {
+               vmballoon_mark_page_online(page, VMW_BALLOON_2M_PAGE);
+
                list_move(&page->lru, pages);
                if (++i == n_req_pages)
                        break;
index bad89b6..345addd 100644 (file)
@@ -310,7 +310,8 @@ int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle)
 
        entry = container_of(resource, struct dbell_entry, resource);
        if (entry->run_delayed) {
-               schedule_work(&entry->work);
+               if (!schedule_work(&entry->work))
+                       vmci_resource_put(resource);
        } else {
                entry->notify_cb(entry->client_data);
                vmci_resource_put(resource);
@@ -361,7 +362,8 @@ static void dbell_fire_entries(u32 notify_idx)
                    atomic_read(&dbell->active) == 1) {
                        if (dbell->run_delayed) {
                                vmci_resource_get(&dbell->resource);
-                               schedule_work(&dbell->work);
+                               if (!schedule_work(&dbell->work))
+                                       vmci_resource_put(&dbell->resource);
                        } else {
                                dbell->notify_cb(dbell->client_data);
                        }
index 74e4364..09113b9 100644 (file)
@@ -564,7 +564,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
        if (index == EXT_CSD_SANITIZE_START)
                cmd.sanitize_busy = true;
 
-       err = mmc_wait_for_cmd(host, &cmd, 0);
+       err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
        if (err)
                goto out;
 
index d681e8a..fe914ff 100644 (file)
@@ -1292,6 +1292,12 @@ int mmc_attach_sd(struct mmc_host *host)
                        goto err;
        }
 
+       /*
+        * Some SD cards claims an out of spec VDD voltage range. Let's treat
+        * these bits as being in-valid and especially also bit7.
+        */
+       ocr &= ~0x7FFF;
+
        rocr = mmc_select_voltage(host, ocr);
 
        /*
index 7e0d3a4..bb31e13 100644 (file)
@@ -597,7 +597,7 @@ static void bcm2835_finish_request(struct bcm2835_host *host)
        struct dma_chan *terminate_chan = NULL;
        struct mmc_request *mrq;
 
-       cancel_delayed_work_sync(&host->timeout_work);
+       cancel_delayed_work(&host->timeout_work);
 
        mrq = host->mrq;
 
index 64d3b5f..4a2872f 100644 (file)
@@ -774,8 +774,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
        /* All SDHI have SDIO status bits which must be 1 */
        mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
 
-       pm_runtime_enable(&pdev->dev);
-
        ret = renesas_sdhi_clk_enable(host);
        if (ret)
                goto efree;
@@ -856,8 +854,6 @@ edisclk:
 efree:
        tmio_mmc_host_free(host);
 
-       pm_runtime_disable(&pdev->dev);
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
@@ -869,8 +865,6 @@ int renesas_sdhi_remove(struct platform_device *pdev)
        tmio_mmc_host_remove(host);
        renesas_sdhi_clk_disable(host);
 
-       pm_runtime_disable(&pdev->dev);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
index 163d1cf..44139fc 100644 (file)
@@ -369,6 +369,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
        host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
        host->mmc_host_ops.hs400_enhanced_strobe =
                                sdhci_cdns_hs400_enhanced_strobe;
+       sdhci_enable_v4_mode(host);
 
        sdhci_get_of_property(pdev);
 
index d4e7e8b..e7d1920 100644 (file)
@@ -357,6 +357,9 @@ static int sdhci_at91_probe(struct platform_device *pdev)
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
 
+       /* HS200 is broken at this moment */
+       host->quirks2 = SDHCI_QUIRK2_BROKEN_HS200;
+
        ret = sdhci_add_host(host);
        if (ret)
                goto pm_runtime_disable;
index 9dc4548..19944b0 100644 (file)
@@ -432,7 +432,6 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
                                        mmc_hostname(host->mmc));
                                host->flags &= ~SDHCI_SIGNALING_330;
                                host->flags |= SDHCI_SIGNALING_180;
-                               host->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
                                host->mmc->caps2 |= MMC_CAP2_NO_SD;
                                host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
                                pci_write_config_dword(chip->pdev,
@@ -682,6 +681,7 @@ static const struct sdhci_ops sdhci_pci_o2_ops = {
 const struct sdhci_pci_fixes sdhci_o2 = {
        .probe = sdhci_pci_o2_probe,
        .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD,
        .probe_slot = sdhci_pci_o2_probe_slot,
 #ifdef CONFIG_PM_SLEEP
        .resume = sdhci_pci_o2_resume,
index 83a4767..d07b979 100644 (file)
@@ -217,10 +217,11 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
        struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
        u32 div, val, mask;
 
-       div = sdhci_sprd_calc_div(sprd_host->base_rate, clk);
+       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
-       clk |= ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
-       sdhci_enable_clk(host, clk);
+       div = sdhci_sprd_calc_div(sprd_host->base_rate, clk);
+       div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
+       sdhci_enable_clk(host, div);
 
        /* enable auto gate sdhc_enable_auto_gate */
        val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
@@ -373,6 +374,11 @@ static unsigned int sdhci_sprd_get_max_timeout_count(struct sdhci_host *host)
        return 1 << 31;
 }
 
+static unsigned int sdhci_sprd_get_ro(struct sdhci_host *host)
+{
+       return 0;
+}
+
 static struct sdhci_ops sdhci_sprd_ops = {
        .read_l = sdhci_sprd_readl,
        .write_l = sdhci_sprd_writel,
@@ -385,6 +391,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
        .set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
        .hw_reset = sdhci_sprd_hw_reset,
        .get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
+       .get_ro = sdhci_sprd_get_ro,
 };
 
 static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -501,9 +508,12 @@ static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
 }
 
 static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
-       .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
+       .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+                 SDHCI_QUIRK_MISSING_CAPS,
        .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
-                  SDHCI_QUIRK2_USE_32BIT_BLK_CNT,
+                  SDHCI_QUIRK2_USE_32BIT_BLK_CNT |
+                  SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .ops = &sdhci_sprd_ops,
 };
 
@@ -605,6 +615,16 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
 
        sdhci_enable_v4_mode(host);
 
+       /*
+        * Supply the existing CAPS, but clear the UHS-I modes. This
+        * will allow these modes to be specified only by device
+        * tree properties through mmc_of_parse().
+        */
+       host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+       host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+       host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
+                        SDHCI_SUPPORT_DDR50);
+
        ret = sdhci_setup_host(host);
        if (ret)
                goto pm_runtime_disable;
index f4d4761..02d8f52 100644 (file)
@@ -258,6 +258,16 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
        }
 }
 
+static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
+{
+       /*
+        * Write-enable shall be assumed if GPIO is missing in a board's
+        * device-tree because SDHCI's WRITE_PROTECT bit doesn't work on
+        * Tegra.
+        */
+       return mmc_gpio_get_ro(host->mmc);
+}
+
 static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1224,6 +1234,7 @@ static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = {
 };
 
 static const struct sdhci_ops tegra_sdhci_ops = {
+       .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
        .write_l    = tegra_sdhci_writel,
        .set_clock  = tegra_sdhci_set_clock,
@@ -1279,6 +1290,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
 };
 
 static const struct sdhci_ops tegra114_sdhci_ops = {
+       .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
        .write_w    = tegra_sdhci_writew,
        .write_l    = tegra_sdhci_writel,
@@ -1332,6 +1344,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
 };
 
 static const struct sdhci_ops tegra210_sdhci_ops = {
+       .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
        .write_w    = tegra210_sdhci_writew,
        .write_l    = tegra_sdhci_writel,
@@ -1366,6 +1379,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
 };
 
 static const struct sdhci_ops tegra186_sdhci_ops = {
+       .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
        .write_l    = tegra_sdhci_writel,
        .set_clock  = tegra_sdhci_set_clock,
index 8539e10..93e83ad 100644 (file)
@@ -172,8 +172,6 @@ static int tmio_mmc_probe(struct platform_device *pdev)
        host->mmc->f_max = pdata->hclk;
        host->mmc->f_min = pdata->hclk / 512;
 
-       pm_runtime_enable(&pdev->dev);
-
        ret = tmio_mmc_host_probe(host);
        if (ret)
                goto host_free;
@@ -193,7 +191,6 @@ host_remove:
        tmio_mmc_host_remove(host);
 host_free:
        tmio_mmc_host_free(host);
-       pm_runtime_disable(&pdev->dev);
 cell_disable:
        if (cell->disable)
                cell->disable(pdev);
@@ -210,8 +207,6 @@ static int tmio_mmc_remove(struct platform_device *pdev)
        if (cell->disable)
                cell->disable(pdev);
 
-       pm_runtime_disable(&pdev->dev);
-
        return 0;
 }
 
index c5ba13f..2f0b092 100644 (file)
@@ -163,6 +163,7 @@ struct tmio_mmc_host {
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
        bool                    native_hotplug;
+       bool                    runtime_synced;
        bool                    sdio_irq_enabled;
 
        /* Mandatory callback */
index 2cb3f95..9b6e100 100644 (file)
@@ -1153,15 +1153,6 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
 
-/**
- * tmio_mmc_host_probe() - Common probe for all implementations
- * @_host: Host to probe
- *
- * Perform tasks common to all implementations probe functions.
- *
- * The caller should have called pm_runtime_enable() prior to calling
- * the common probe function.
- */
 int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 {
        struct platform_device *pdev = _host->pdev;
@@ -1257,19 +1248,22 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       pm_runtime_set_active(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        ret = mmc_add_host(mmc);
        if (ret)
                goto remove_host;
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
+       pm_runtime_put(&pdev->dev);
 
        return 0;
 
 remove_host:
+       pm_runtime_put_noidle(&pdev->dev);
        tmio_mmc_host_remove(_host);
        return ret;
 }
@@ -1280,12 +1274,11 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        struct platform_device *pdev = host->pdev;
        struct mmc_host *mmc = host->mmc;
 
+       pm_runtime_get_sync(&pdev->dev);
+
        if (host->pdata->flags & TMIO_MMC_SDIO_IRQ)
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
 
-       if (!host->native_hotplug)
-               pm_runtime_get_sync(&pdev->dev);
-
        dev_pm_qos_hide_latency_limit(&pdev->dev);
 
        mmc_remove_host(mmc);
@@ -1294,7 +1287,10 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        tmio_mmc_release_dma(host);
 
        pm_runtime_dont_use_autosuspend(&pdev->dev);
+       if (host->native_hotplug)
+               pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
 
@@ -1337,6 +1333,11 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 {
        struct tmio_mmc_host *host = dev_get_drvdata(dev);
 
+       if (!host->runtime_synced) {
+               host->runtime_synced = true;
+               return 0;
+       }
+
        tmio_mmc_clk_enable(host);
        tmio_mmc_hw_reset(host->mmc);
 
index 49aad9a..91a2be4 100644 (file)
@@ -631,7 +631,6 @@ static int uniphier_sd_probe(struct platform_device *pdev)
        host->clk_disable = uniphier_sd_clk_disable;
        host->set_clock = uniphier_sd_set_clock;
 
-       pm_runtime_enable(&pdev->dev);
        ret = uniphier_sd_clk_enable(host);
        if (ret)
                goto free_host;
@@ -653,7 +652,6 @@ static int uniphier_sd_probe(struct platform_device *pdev)
 
 free_host:
        tmio_mmc_host_free(host);
-       pm_runtime_disable(&pdev->dev);
 
        return ret;
 }
@@ -664,7 +662,6 @@ static int uniphier_sd_remove(struct platform_device *pdev)
 
        tmio_mmc_host_remove(host);
        uniphier_sd_clk_disable(host);
-       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index b4e3caf..a4d8968 100644 (file)
@@ -1,5 +1,6 @@
 menuconfig MTD_HYPERBUS
        tristate "HyperBus support"
+       depends on HAS_IOMEM
        select MTD_CFI
        select MTD_MAP_BANK_WIDTH_2
        select MTD_CFI_AMDSTD
index 895510d..47602af 100644 (file)
@@ -81,6 +81,7 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r
        default:
                printk(KERN_WARNING "SA1100 flash: unknown base address "
                       "0x%08lx, assuming CS0\n", phys);
+               /* Fall through */
 
        case SA1100_CS0_PHYS:
                subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
index 03cc788..654bdc4 100644 (file)
@@ -3780,8 +3780,6 @@ static int spi_nor_init_params(struct spi_nor *nor,
                default:
                        /* Kept only for backward compatibility purpose. */
                        params->quad_enable = spansion_quad_enable;
-                       if (nor->clear_sr_bp)
-                               nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
                        break;
                }
 
@@ -4035,6 +4033,9 @@ static int spi_nor_init(struct spi_nor *nor)
        int err;
 
        if (nor->clear_sr_bp) {
+               if (nor->quad_enable == spansion_quad_enable)
+                       nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
+
                err = nor->clear_sr_bp(nor);
                if (err) {
                        dev_err(nor->dev,
index 02fd782..931d9d9 100644 (file)
@@ -1126,6 +1126,8 @@ static void bond_compute_features(struct bonding *bond)
 done:
        bond_dev->vlan_features = vlan_features;
        bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
+                                   NETIF_F_HW_VLAN_CTAG_TX |
+                                   NETIF_F_HW_VLAN_STAG_TX |
                                    NETIF_F_GSO_UDP_L4;
        bond_dev->mpls_features = mpls_features;
        bond_dev->gso_max_segs = gso_max_segs;
index 3811fdb..28c963a 100644 (file)
@@ -478,6 +478,7 @@ static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port,
                                unsigned long *supported,
                                struct phylink_link_state *state)
 {
+       struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
        __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 
        if (!phy_interface_mode_is_rgmii(state->interface) &&
@@ -487,8 +488,10 @@ static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port,
            state->interface != PHY_INTERFACE_MODE_INTERNAL &&
            state->interface != PHY_INTERFACE_MODE_MOCA) {
                bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
-               dev_err(ds->dev,
-                       "Unsupported interface: %d\n", state->interface);
+               if (port != core_readl(priv, CORE_IMP0_PRT_ID))
+                       dev_err(ds->dev,
+                               "Unsupported interface: %d for port %d\n",
+                               state->interface, port);
                return;
        }
 
@@ -526,6 +529,9 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port,
        u32 id_mode_dis = 0, port_mode;
        u32 reg, offset;
 
+       if (port == core_readl(priv, CORE_IMP0_PRT_ID))
+               return;
+
        if (priv->type == BCM7445_DEVICE_ID)
                offset = CORE_STS_OVERRIDE_GMIIP_PORT(port);
        else
index 5a9e27b..098b01e 100644 (file)
@@ -81,6 +81,7 @@ static const struct of_device_id ksz9477_dt_ids[] = {
        { .compatible = "microchip,ksz9897" },
        { .compatible = "microchip,ksz9893" },
        { .compatible = "microchip,ksz9563" },
+       { .compatible = "microchip,ksz8563" },
        {},
 };
 MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
index ee7096d..72ec250 100644 (file)
@@ -128,6 +128,7 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset,
 
 #define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign)                \
        {                                                               \
+               .name = #width,                                         \
                .val_bits = (width),                                    \
                .reg_stride = (width) / 8,                              \
                .reg_bits = (regbits) + (regalign),                     \
index d073baf..df976b2 100644 (file)
@@ -1223,12 +1223,8 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
 {
        struct sja1105_private *priv = ds->priv;
        struct device *dev = ds->dev;
-       u16 rx_vid, tx_vid;
        int i;
 
-       rx_vid = dsa_8021q_rx_vid(ds, port);
-       tx_vid = dsa_8021q_tx_vid(ds, port);
-
        for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
                struct sja1105_l2_lookup_entry l2_lookup = {0};
                u8 macaddr[ETH_ALEN];
index b41f236..7ce9c69 100644 (file)
@@ -469,13 +469,19 @@ static int __init xgbe_mod_init(void)
 
        ret = xgbe_platform_init();
        if (ret)
-               return ret;
+               goto err_platform_init;
 
        ret = xgbe_pci_init();
        if (ret)
-               return ret;
+               goto err_pci_init;
 
        return 0;
+
+err_pci_init:
+       xgbe_platform_exit();
+err_platform_init:
+       unregister_netdevice_notifier(&xgbe_netdev_notifier);
+       return ret;
 }
 
 static void __exit xgbe_mod_exit(void)
index 440690b..aee827f 100644 (file)
@@ -431,7 +431,8 @@ int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id)
                if (be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id)
                        break;
        }
-       if (rule && be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id) {
+       if (rule && rule->type == aq_rx_filter_vlan &&
+           be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id) {
                struct ethtool_rxnfc cmd;
 
                cmd.fs.location = rule->aq_fsp.location;
@@ -843,7 +844,7 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
                return err;
 
        if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
-               if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) {
+               if (hweight <= AQ_VLAN_MAX_FILTERS && hweight > 0) {
                        err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
                                !(aq_nic->packet_filter & IFF_PROMISC));
                        aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
index 100722a..b4a0fb2 100644 (file)
@@ -61,6 +61,10 @@ static int aq_ndev_open(struct net_device *ndev)
        if (err < 0)
                goto err_exit;
 
+       err = aq_filters_vlans_update(aq_nic);
+       if (err < 0)
+               goto err_exit;
+
        err = aq_nic_start(aq_nic);
        if (err < 0)
                goto err_exit;
index e139276..8f66e78 100644 (file)
@@ -393,7 +393,7 @@ int aq_nic_start(struct aq_nic_s *self)
                                                   self->aq_nic_cfg.link_irq_vec);
                        err = request_threaded_irq(irqvec, NULL,
                                                   aq_linkstate_threaded_isr,
-                                                  IRQF_SHARED,
+                                                  IRQF_SHARED | IRQF_ONESHOT,
                                                   self->ndev->name, self);
                        if (err < 0)
                                goto err_exit;
index 715685a..28892b8 100644 (file)
@@ -86,6 +86,7 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
                        }
                }
 
+err_exit:
                if (!was_tx_cleaned)
                        work_done = budget;
 
@@ -95,7 +96,7 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
                                        1U << self->aq_ring_param.vec_idx);
                }
        }
-err_exit:
+
        return work_done;
 }
 
index e47ea92..d10b421 100644 (file)
@@ -3057,12 +3057,13 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        /* if VF indicate to PF this function is going down (PF will delete sp
         * elements and clear initializations
         */
-       if (IS_VF(bp))
+       if (IS_VF(bp)) {
+               bnx2x_clear_vlan_info(bp);
                bnx2x_vfpf_close_vf(bp);
-       else if (unload_mode != UNLOAD_RECOVERY)
+       } else if (unload_mode != UNLOAD_RECOVERY) {
                /* if this is a normal/close unload need to clean up chip*/
                bnx2x_chip_cleanup(bp, unload_mode, keep_link);
-       else {
+       else {
                /* Send the UNLOAD_REQUEST to the MCP */
                bnx2x_send_unload_req(bp, unload_mode);
 
index c2f6e44..8b08cb1 100644 (file)
@@ -425,6 +425,8 @@ void bnx2x_set_reset_global(struct bnx2x *bp);
 void bnx2x_disable_close_the_gate(struct bnx2x *bp);
 int bnx2x_init_hw_func_cnic(struct bnx2x *bp);
 
+void bnx2x_clear_vlan_info(struct bnx2x *bp);
+
 /**
  * bnx2x_sp_event - handle ramrods completion.
  *
index 2cc14db..192ff8d 100644 (file)
@@ -8482,11 +8482,21 @@ int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
        return rc;
 }
 
+void bnx2x_clear_vlan_info(struct bnx2x *bp)
+{
+       struct bnx2x_vlan_entry *vlan;
+
+       /* Mark that hw forgot all entries */
+       list_for_each_entry(vlan, &bp->vlan_reg, link)
+               vlan->hw = false;
+
+       bp->vlan_cnt = 0;
+}
+
 static int bnx2x_del_all_vlans(struct bnx2x *bp)
 {
        struct bnx2x_vlan_mac_obj *vlan_obj = &bp->sp_objs[0].vlan_obj;
        unsigned long ramrod_flags = 0, vlan_flags = 0;
-       struct bnx2x_vlan_entry *vlan;
        int rc;
 
        __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
@@ -8495,10 +8505,7 @@ static int bnx2x_del_all_vlans(struct bnx2x *bp)
        if (rc)
                return rc;
 
-       /* Mark that hw forgot all entries */
-       list_for_each_entry(vlan, &bp->vlan_reg, link)
-               vlan->hw = false;
-       bp->vlan_cnt = 0;
+       bnx2x_clear_vlan_info(bp);
 
        return 0;
 }
index 7070349..8dce406 100644 (file)
@@ -2021,9 +2021,9 @@ static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi)
        if (bnapi->events & BNXT_RX_EVENT) {
                struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
 
-               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                if (bnapi->events & BNXT_AGG_EVENT)
                        bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
+               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
        }
        bnapi->events = 0;
 }
@@ -5064,6 +5064,7 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
 
 static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
 {
+       bool agg_rings = !!(bp->flags & BNXT_FLAG_AGG_RINGS);
        int i, rc = 0;
        u32 type;
 
@@ -5139,7 +5140,9 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                if (rc)
                        goto err_out;
                bnxt_set_db(bp, &rxr->rx_db, type, map_idx, ring->fw_ring_id);
-               bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
+               /* If we have agg rings, post agg buffers first. */
+               if (!agg_rings)
+                       bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
                if (bp->flags & BNXT_FLAG_CHIP_P5) {
                        struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
@@ -5158,7 +5161,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                }
        }
 
-       if (bp->flags & BNXT_FLAG_AGG_RINGS) {
+       if (agg_rings) {
                type = HWRM_RING_ALLOC_AGG;
                for (i = 0; i < bp->rx_nr_rings; i++) {
                        struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
@@ -5174,6 +5177,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
                        bnxt_set_db(bp, &rxr->rx_agg_db, type, map_idx,
                                    ring->fw_ring_id);
                        bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
+                       bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
                        bp->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id;
                }
        }
@@ -7016,19 +7020,29 @@ static void bnxt_hwrm_clear_vnic_rss(struct bnxt *bp)
                bnxt_hwrm_vnic_set_rss(bp, i, false);
 }
 
-static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
-                                   bool irq_re_init)
+static void bnxt_clear_vnic(struct bnxt *bp)
 {
-       if (bp->vnic_info) {
-               bnxt_hwrm_clear_vnic_filter(bp);
+       if (!bp->vnic_info)
+               return;
+
+       bnxt_hwrm_clear_vnic_filter(bp);
+       if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
                /* clear all RSS setting before free vnic ctx */
                bnxt_hwrm_clear_vnic_rss(bp);
                bnxt_hwrm_vnic_ctx_free(bp);
-               /* before free the vnic, undo the vnic tpa settings */
-               if (bp->flags & BNXT_FLAG_TPA)
-                       bnxt_set_tpa(bp, false);
-               bnxt_hwrm_vnic_free(bp);
        }
+       /* before free the vnic, undo the vnic tpa settings */
+       if (bp->flags & BNXT_FLAG_TPA)
+               bnxt_set_tpa(bp, false);
+       bnxt_hwrm_vnic_free(bp);
+       if (bp->flags & BNXT_FLAG_CHIP_P5)
+               bnxt_hwrm_vnic_ctx_free(bp);
+}
+
+static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
+                                   bool irq_re_init)
+{
+       bnxt_clear_vnic(bp);
        bnxt_hwrm_ring_free(bp, close_path);
        bnxt_hwrm_ring_grp_free(bp);
        if (irq_re_init) {
index 549c90d..c05d663 100644 (file)
@@ -98,10 +98,13 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
        if (idx)
                req->dimensions = cpu_to_le16(1);
 
-       if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE))
+       if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
                memcpy(data_addr, buf, bytesize);
-
-       rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
+               rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
+       } else {
+               rc = hwrm_send_message_silent(bp, msg, msg_len,
+                                             HWRM_CMD_TIMEOUT);
+       }
        if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
                memcpy(buf, data_addr, bytesize);
 
index c7ee63d..8445a0c 100644 (file)
@@ -2016,21 +2016,19 @@ static int bnxt_flash_package_from_file(struct net_device *dev,
        mutex_lock(&bp->hwrm_cmd_lock);
        hwrm_err = _hwrm_send_message(bp, &install, sizeof(install),
                                      INSTALL_PACKAGE_TIMEOUT);
-       if (hwrm_err)
-               goto flash_pkg_exit;
-
-       if (resp->error_code) {
+       if (hwrm_err) {
                u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
 
-               if (error_code == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
+               if (resp->error_code && error_code ==
+                   NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
                        install.flags |= cpu_to_le16(
                               NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
                        hwrm_err = _hwrm_send_message(bp, &install,
                                                      sizeof(install),
                                                      INSTALL_PACKAGE_TIMEOUT);
-                       if (hwrm_err)
-                               goto flash_pkg_exit;
                }
+               if (hwrm_err)
+                       goto flash_pkg_exit;
        }
 
        if (resp->result) {
index 6fe4a71..dd621f6 100644 (file)
@@ -1236,7 +1236,7 @@ static int __bnxt_tc_del_flow(struct bnxt *bp,
 static void bnxt_tc_set_flow_dir(struct bnxt *bp, struct bnxt_tc_flow *flow,
                                 u16 src_fid)
 {
-       flow->dir = (bp->pf.fw_fid == src_fid) ? BNXT_DIR_RX : BNXT_DIR_TX;
+       flow->l2_key.dir = (bp->pf.fw_fid == src_fid) ? BNXT_DIR_RX : BNXT_DIR_TX;
 }
 
 static void bnxt_tc_set_src_fid(struct bnxt *bp, struct bnxt_tc_flow *flow,
@@ -1285,9 +1285,7 @@ static int bnxt_tc_add_flow(struct bnxt *bp, u16 src_fid,
                goto free_node;
 
        bnxt_tc_set_src_fid(bp, flow, src_fid);
-
-       if (bp->fw_cap & BNXT_FW_CAP_OVS_64BIT_HANDLE)
-               bnxt_tc_set_flow_dir(bp, flow, src_fid);
+       bnxt_tc_set_flow_dir(bp, flow, flow->src_fid);
 
        if (!bnxt_tc_can_offload(bp, flow)) {
                rc = -EOPNOTSUPP;
@@ -1407,7 +1405,7 @@ static void bnxt_fill_cfa_stats_req(struct bnxt *bp,
                 * 2. 15th bit of flow_handle must specify the flow
                 *    direction (TX/RX).
                 */
-               if (flow_node->flow.dir == BNXT_DIR_RX)
+               if (flow_node->flow.l2_key.dir == BNXT_DIR_RX)
                        handle = CFA_FLOW_INFO_REQ_FLOW_HANDLE_DIR_RX |
                                 CFA_FLOW_INFO_REQ_FLOW_HANDLE_MAX_MASK;
                else
index ffec57d..4f05305 100644 (file)
@@ -23,6 +23,9 @@ struct bnxt_tc_l2_key {
        __be16          inner_vlan_tci;
        __be16          ether_type;
        u8              num_vlans;
+       u8              dir;
+#define BNXT_DIR_RX    1
+#define BNXT_DIR_TX    0
 };
 
 struct bnxt_tc_l3_key {
@@ -98,9 +101,6 @@ struct bnxt_tc_flow {
 
        /* flow applicable to pkts ingressing on this fid */
        u16                             src_fid;
-       u8                              dir;
-#define BNXT_DIR_RX    1
-#define BNXT_DIR_TX    0
        struct bnxt_tc_l2_key           l2_key;
        struct bnxt_tc_l2_key           l2_mask;
        struct bnxt_tc_l3_key           l3_key;
index d3a0b61..b221968 100644 (file)
@@ -1124,6 +1124,7 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = {
        .set_coalesce           = bcmgenet_set_coalesce,
        .get_link_ksettings     = bcmgenet_get_link_ksettings,
        .set_link_ksettings     = bcmgenet_set_link_ksettings,
+       .get_ts_info            = ethtool_op_get_ts_info,
 };
 
 /* Power down the unimac, based on mode. */
index 5ca17e6..35b59b5 100644 (file)
@@ -4154,7 +4154,7 @@ static const struct of_device_id macb_dt_ids[] = {
        { .compatible = "cdns,emac", .data = &emac_config },
        { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
        { .compatible = "cdns,zynq-gem", .data = &zynq_config },
-       { .compatible = "sifive,fu540-macb", .data = &fu540_c000_config },
+       { .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, macb_dt_ids);
index 73632b8..b821c9e 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "cavium_ptp.h"
 
-#define DRV_NAME       "Cavium PTP Driver"
+#define DRV_NAME "cavium_ptp"
 
 #define PCI_DEVICE_ID_CAVIUM_PTP       0xA00C
 #define PCI_DEVICE_ID_CAVIUM_RST       0xA00E
index 0322241..6dd65f9 100644 (file)
@@ -237,8 +237,10 @@ int octeon_setup_iq(struct octeon_device *oct,
        }
 
        oct->num_iqs++;
-       if (oct->fn_list.enable_io_queues(oct))
+       if (oct->fn_list.enable_io_queues(oct)) {
+               octeon_delete_instr_queue(oct, iq_no);
                return 1;
+       }
 
        return 0;
 }
index 0295903..d692251 100644 (file)
@@ -3236,8 +3236,10 @@ static ssize_t blocked_fl_write(struct file *filp, const char __user *ubuf,
                return -ENOMEM;
 
        err = bitmap_parse_user(ubuf, count, t, adap->sge.egr_sz);
-       if (err)
+       if (err) {
+               kvfree(t);
                return err;
+       }
 
        bitmap_copy(adap->sge.blocked_fl, t, adap->sge.egr_sz);
        kvfree(t);
index 133acca..092da2d 100644 (file)
@@ -167,7 +167,7 @@ struct nps_enet_priv {
 };
 
 /**
- * nps_reg_set - Sets ENET register with provided value.
+ * nps_enet_reg_set - Sets ENET register with provided value.
  * @priv:       Pointer to EZchip ENET private data structure.
  * @reg:        Register offset from base address.
  * @value:      Value to set in register.
@@ -179,7 +179,7 @@ static inline void nps_enet_reg_set(struct nps_enet_priv *priv,
 }
 
 /**
- * nps_reg_get - Gets value of specified ENET register.
+ * nps_enet_reg_get - Gets value of specified ENET register.
  * @priv:       Pointer to EZchip ENET private data structure.
  * @reg:        Register offset from base address.
  *
index 2fd2586..bc59489 100644 (file)
@@ -82,7 +82,7 @@ static int enetc_ptp_probe(struct pci_dev *pdev,
        n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
        if (n != 1) {
                err = -EPERM;
-               goto err_irq;
+               goto err_irq_vectors;
        }
 
        ptp_qoriq->irq = pci_irq_vector(pdev, 0);
@@ -107,6 +107,8 @@ static int enetc_ptp_probe(struct pci_dev *pdev,
 err_no_clock:
        free_irq(ptp_qoriq->irq, ptp_qoriq);
 err_irq:
+       pci_free_irq_vectors(pdev);
+err_irq_vectors:
        iounmap(base);
 err_ioremap:
        kfree(ptp_qoriq);
@@ -125,6 +127,7 @@ static void enetc_ptp_remove(struct pci_dev *pdev)
 
        enetc_phc_index = -1;
        ptp_qoriq_free(ptp_qoriq);
+       pci_free_irq_vectors(pdev);
        kfree(ptp_qoriq);
 
        pci_release_mem_regions(pdev);
index 4972987..aca95f6 100644 (file)
@@ -50,7 +50,7 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
                                  u64_stats_fetch_begin(&priv->tx[ring].statss);
                                s->tx_packets += priv->tx[ring].pkt_done;
                                s->tx_bytes += priv->tx[ring].bytes_done;
-                       } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+                       } while (u64_stats_fetch_retry(&priv->tx[ring].statss,
                                                       start));
                }
        }
index 0a72438..85a3b06 100644 (file)
@@ -98,7 +98,7 @@ static const struct hclge_hw_error hclge_igu_egu_tnl_int[] = {
          .reset_level = HNAE3_GLOBAL_RESET },
        { .int_msk = BIT(1), .msg = "rx_stp_fifo_overflow",
          .reset_level = HNAE3_GLOBAL_RESET },
-       { .int_msk = BIT(2), .msg = "rx_stp_fifo_undeflow",
+       { .int_msk = BIT(2), .msg = "rx_stp_fifo_underflow",
          .reset_level = HNAE3_GLOBAL_RESET },
        { .int_msk = BIT(3), .msg = "tx_buf_overflow",
          .reset_level = HNAE3_GLOBAL_RESET },
index d654c23..c5be4eb 100644 (file)
@@ -1605,7 +1605,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
        struct net_device *netdev;
        struct ibmveth_adapter *adapter;
        unsigned char *mac_addr_p;
-       unsigned int *mcastFilterSize_p;
+       __be32 *mcastFilterSize_p;
        long ret;
        unsigned long ret_attr;
 
@@ -1627,8 +1627,9 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
                return -EINVAL;
        }
 
-       mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
-                                               VETH_MCAST_FILTER_SIZE, NULL);
+       mcastFilterSize_p = (__be32 *)vio_get_attribute(dev,
+                                                       VETH_MCAST_FILTER_SIZE,
+                                                       NULL);
        if (!mcastFilterSize_p) {
                dev_err(&dev->dev, "Can't find VETH_MCAST_FILTER_SIZE "
                        "attribute\n");
@@ -1645,7 +1646,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        adapter->vdev = dev;
        adapter->netdev = netdev;
-       adapter->mcastFilterSize = *mcastFilterSize_p;
+       adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p);
        adapter->pool_config = 0;
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
index 3da6800..5cb55ea 100644 (file)
@@ -1568,6 +1568,8 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
                lpar_rc = send_subcrq_indirect(adapter, handle_array[queue_num],
                                               (u64)tx_buff->indir_dma,
                                               (u64)num_entries);
+               dma_unmap_single(dev, tx_buff->indir_dma,
+                                sizeof(tx_buff->indir_arr), DMA_TO_DEVICE);
        } else {
                tx_buff->num_entries = num_entries;
                lpar_rc = send_subcrq(adapter, handle_array[queue_num],
@@ -1981,6 +1983,13 @@ static void __ibmvnic_reset(struct work_struct *work)
 
        rwi = get_next_rwi(adapter);
        while (rwi) {
+               if (adapter->state == VNIC_REMOVING ||
+                   adapter->state == VNIC_REMOVED) {
+                       kfree(rwi);
+                       rc = EBUSY;
+                       break;
+               }
+
                if (adapter->force_reset_recovery) {
                        adapter->force_reset_recovery = false;
                        rc = do_hard_reset(adapter, rwi, reset_state);
@@ -2788,7 +2797,6 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
        union sub_crq *next;
        int index;
        int i, j;
-       u8 *first;
 
 restart_loop:
        while (pending_scrq(adapter, scrq)) {
@@ -2818,14 +2826,6 @@ restart_loop:
 
                                txbuff->data_dma[j] = 0;
                        }
-                       /* if sub_crq was sent indirectly */
-                       first = &txbuff->indir_arr[0].generic.first;
-                       if (*first == IBMVNIC_CRQ_CMD) {
-                               dma_unmap_single(dev, txbuff->indir_dma,
-                                                sizeof(txbuff->indir_arr),
-                                                DMA_TO_DEVICE);
-                               *first = 0;
-                       }
 
                        if (txbuff->last_frag) {
                                dev_kfree_skb_any(txbuff->skb);
index cbaf712..51c696b 100644 (file)
@@ -36,6 +36,7 @@
 #include <net/vxlan.h>
 #include <net/mpls.h>
 #include <net/xdp_sock.h>
+#include <net/xfrm.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
@@ -2621,7 +2622,7 @@ adjust_by_size:
                /* 16K ints/sec to 9.2K ints/sec */
                avg_wire_size *= 15;
                avg_wire_size += 11452;
-       } else if (avg_wire_size <= 1980) {
+       } else if (avg_wire_size < 1968) {
                /* 9.2K ints/sec to 8K ints/sec */
                avg_wire_size *= 5;
                avg_wire_size += 22420;
@@ -2654,6 +2655,8 @@ adjust_by_size:
        case IXGBE_LINK_SPEED_2_5GB_FULL:
        case IXGBE_LINK_SPEED_1GB_FULL:
        case IXGBE_LINK_SPEED_10_FULL:
+               if (avg_wire_size > 8064)
+                       avg_wire_size = 8064;
                itr += DIV_ROUND_UP(avg_wire_size,
                                    IXGBE_ITR_ADAPTIVE_MIN_INC * 64) *
                       IXGBE_ITR_ADAPTIVE_MIN_INC;
@@ -7897,11 +7900,8 @@ static void ixgbe_service_task(struct work_struct *work)
                return;
        }
        if (ixgbe_check_fw_error(adapter)) {
-               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
-                       rtnl_lock();
+               if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        unregister_netdev(adapter->netdev);
-                       rtnl_unlock();
-               }
                ixgbe_service_event_complete(adapter);
                return;
        }
@@ -8698,7 +8698,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
 #endif /* IXGBE_FCOE */
 
 #ifdef CONFIG_IXGBE_IPSEC
-       if (secpath_exists(skb) &&
+       if (xfrm_offload(skb) &&
            !ixgbe_ipsec_tx(tx_ring, first, &ipsec_tx))
                goto out_drop;
 #endif
index 6b60955..a3b6d8c 100644 (file)
@@ -633,19 +633,17 @@ static void ixgbe_clean_xdp_tx_buffer(struct ixgbe_ring *tx_ring,
 bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
                            struct ixgbe_ring *tx_ring, int napi_budget)
 {
+       u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use;
        unsigned int total_packets = 0, total_bytes = 0;
-       u32 i = tx_ring->next_to_clean, xsk_frames = 0;
-       unsigned int budget = q_vector->tx.work_limit;
        struct xdp_umem *umem = tx_ring->xsk_umem;
        union ixgbe_adv_tx_desc *tx_desc;
        struct ixgbe_tx_buffer *tx_bi;
-       bool xmit_done;
+       u32 xsk_frames = 0;
 
-       tx_bi = &tx_ring->tx_buffer_info[i];
-       tx_desc = IXGBE_TX_DESC(tx_ring, i);
-       i -= tx_ring->count;
+       tx_bi = &tx_ring->tx_buffer_info[ntc];
+       tx_desc = IXGBE_TX_DESC(tx_ring, ntc);
 
-       do {
+       while (ntc != ntu) {
                if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
                        break;
 
@@ -661,22 +659,18 @@ bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
 
                tx_bi++;
                tx_desc++;
-               i++;
-               if (unlikely(!i)) {
-                       i -= tx_ring->count;
+               ntc++;
+               if (unlikely(ntc == tx_ring->count)) {
+                       ntc = 0;
                        tx_bi = tx_ring->tx_buffer_info;
                        tx_desc = IXGBE_TX_DESC(tx_ring, 0);
                }
 
                /* issue prefetch for next Tx descriptor */
                prefetch(tx_desc);
+       }
 
-               /* update budget accounting */
-               budget--;
-       } while (likely(budget));
-
-       i += tx_ring->count;
-       tx_ring->next_to_clean = i;
+       tx_ring->next_to_clean = ntc;
 
        u64_stats_update_begin(&tx_ring->syncp);
        tx_ring->stats.bytes += total_bytes;
@@ -688,8 +682,7 @@ bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
        if (xsk_frames)
                xsk_umem_complete_tx(umem, xsk_frames);
 
-       xmit_done = ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit);
-       return budget > 0 && xmit_done;
+       return ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit);
 }
 
 int ixgbe_xsk_async_xmit(struct net_device *dev, u32 qid)
index d2b41f9..72872d6 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/bpf.h>
 #include <linux/bpf_trace.h>
 #include <linux/atomic.h>
+#include <net/xfrm.h>
 
 #include "ixgbevf.h"
 
@@ -4161,7 +4162,7 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb,
        first->protocol = vlan_get_protocol(skb);
 
 #ifdef CONFIG_IXGBEVF_IPSEC
-       if (secpath_exists(skb) && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx))
+       if (xfrm_offload(skb) && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx))
                goto out_drop;
 #endif
        tso = ixgbevf_tso(tx_ring, first, &hdr_len, &ipsec_tx);
index a01c75e..e036387 100644 (file)
@@ -4931,6 +4931,13 @@ static const struct dmi_system_id msi_blacklist[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "P6T"),
                },
        },
+       {
+               .ident = "ASUS P6X",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "P6X"),
+               },
+       },
        {}
 };
 
index 6c01314..db3552f 100644 (file)
@@ -1187,7 +1187,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, rss_map->indir_qp);
        if (err) {
                en_err(priv, "Failed to allocate RSS indirection QP\n");
-               goto rss_err;
+               goto qp_alloc_err;
        }
 
        rss_map->indir_qp->event = mlx4_en_sqp_event;
@@ -1241,6 +1241,7 @@ indir_err:
                       MLX4_QP_STATE_RST, NULL, 0, 0, rss_map->indir_qp);
        mlx4_qp_remove(mdev->dev, rss_map->indir_qp);
        mlx4_qp_free(mdev->dev, rss_map->indir_qp);
+qp_alloc_err:
        kfree(rss_map->indir_qp);
        rss_map->indir_qp = NULL;
 rss_err:
index 1f6e16d..309470e 100644 (file)
@@ -2240,7 +2240,7 @@ static int mlx4_validate_optimized_steering(struct mlx4_dev *dev)
        for (i = 1; i <= dev->caps.num_ports; i++) {
                if (mlx4_dev_port(dev, i, &port_cap)) {
                        mlx4_err(dev,
-                                "QUERY_DEV_CAP command failed, can't veify DMFS high rate steering.\n");
+                                "QUERY_DEV_CAP command failed, can't verify DMFS high rate steering.\n");
                } else if ((dev->caps.dmfs_high_steer_mode !=
                            MLX4_STEERING_DMFS_A0_DEFAULT) &&
                           (port_cap.dmfs_optimized_state ==
index ce1be2a..65bec19 100644 (file)
@@ -184,8 +184,13 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
-       struct mlx5_wqe_eth_seg  eth;
-       struct mlx5_wqe_data_seg data[0];
+       union {
+               struct {
+                       struct mlx5_wqe_eth_seg  eth;
+                       struct mlx5_wqe_data_seg data[0];
+               };
+               u8 tls_progress_params_ctx[0];
+       };
 };
 
 struct mlx5e_rx_wqe_ll {
@@ -1100,6 +1105,8 @@ u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
 u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
 int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
                              struct ethtool_ts_info *info);
+int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
+                              struct ethtool_flash *flash);
 void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv,
                                  struct ethtool_pauseparam *pauseparam);
 int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
index f3d9874..c7f8645 100644 (file)
@@ -76,26 +76,21 @@ static int mlx5e_tx_reporter_err_cqe_recover(struct mlx5e_txqsq *sq)
        u8 state;
        int err;
 
-       if (!test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
-               return 0;
-
        err = mlx5_core_query_sq_state(mdev, sq->sqn, &state);
        if (err) {
                netdev_err(dev, "Failed to query SQ 0x%x state. err = %d\n",
                           sq->sqn, err);
-               return err;
+               goto out;
        }
 
-       if (state != MLX5_SQC_STATE_ERR) {
-               netdev_err(dev, "SQ 0x%x not in ERROR state\n", sq->sqn);
-               return -EINVAL;
-       }
+       if (state != MLX5_SQC_STATE_ERR)
+               goto out;
 
        mlx5e_tx_disable_queue(sq->txq);
 
        err = mlx5e_wait_for_sq_flush(sq);
        if (err)
-               return err;
+               goto out;
 
        /* At this point, no new packets will arrive from the stack as TXQ is
         * marked with QUEUE_STATE_DRV_XOFF. In addition, NAPI cleared all
@@ -104,13 +99,17 @@ static int mlx5e_tx_reporter_err_cqe_recover(struct mlx5e_txqsq *sq)
 
        err = mlx5e_sq_to_ready(sq, state);
        if (err)
-               return err;
+               goto out;
 
        mlx5e_reset_txqsq_cc_pc(sq);
        sq->stats->recover++;
+       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
        mlx5e_activate_txqsq(sq);
 
        return 0;
+out:
+       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
+       return err;
 }
 
 static int mlx5_tx_health_report(struct devlink_health_reporter *tx_reporter,
index aaffa6f..7f78c00 100644 (file)
@@ -143,7 +143,10 @@ void mlx5e_activate_xsk(struct mlx5e_channel *c)
 {
        set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
        /* TX queue is created active. */
+
+       spin_lock(&c->xskicosq_lock);
        mlx5e_trigger_irq(&c->xskicosq);
+       spin_unlock(&c->xskicosq_lock);
 }
 
 void mlx5e_deactivate_xsk(struct mlx5e_channel *c)
index 407da83..b7298f9 100644 (file)
 #include "accel/tls.h"
 
 #define MLX5E_KTLS_STATIC_UMR_WQE_SZ \
-       (sizeof(struct mlx5e_umr_wqe) + MLX5_ST_SZ_BYTES(tls_static_params))
+       (offsetof(struct mlx5e_umr_wqe, tls_static_params_ctx) + \
+        MLX5_ST_SZ_BYTES(tls_static_params))
 #define MLX5E_KTLS_STATIC_WQEBBS \
        (DIV_ROUND_UP(MLX5E_KTLS_STATIC_UMR_WQE_SZ, MLX5_SEND_WQE_BB))
 
 #define MLX5E_KTLS_PROGRESS_WQE_SZ \
-       (sizeof(struct mlx5e_tx_wqe) + MLX5_ST_SZ_BYTES(tls_progress_params))
+       (offsetof(struct mlx5e_tx_wqe, tls_progress_params_ctx) + \
+        MLX5_ST_SZ_BYTES(tls_progress_params))
 #define MLX5E_KTLS_PROGRESS_WQEBBS \
        (DIV_ROUND_UP(MLX5E_KTLS_PROGRESS_WQE_SZ, MLX5_SEND_WQE_BB))
 #define MLX5E_KTLS_MAX_DUMP_WQEBBS 2
index 3766545..7833dde 100644 (file)
@@ -69,7 +69,7 @@ build_static_params(struct mlx5e_umr_wqe *wqe, u16 pc, u32 sqn,
        cseg->qpn_ds           = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
                                             STATIC_PARAMS_DS_CNT);
        cseg->fm_ce_se         = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
-       cseg->imm              = cpu_to_be32(priv_tx->tisn);
+       cseg->tisn             = cpu_to_be32(priv_tx->tisn << 8);
 
        ucseg->flags = MLX5_UMR_INLINE;
        ucseg->bsf_octowords = cpu_to_be16(MLX5_ST_SZ_BYTES(tls_static_params) / 16);
@@ -80,7 +80,7 @@ build_static_params(struct mlx5e_umr_wqe *wqe, u16 pc, u32 sqn,
 static void
 fill_progress_params_ctx(void *ctx, struct mlx5e_ktls_offload_context_tx *priv_tx)
 {
-       MLX5_SET(tls_progress_params, ctx, pd, priv_tx->tisn);
+       MLX5_SET(tls_progress_params, ctx, tisn, priv_tx->tisn);
        MLX5_SET(tls_progress_params, ctx, record_tracker_state,
                 MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START);
        MLX5_SET(tls_progress_params, ctx, auth_state,
@@ -104,18 +104,20 @@ build_progress_params(struct mlx5e_tx_wqe *wqe, u16 pc, u32 sqn,
                                             PROGRESS_PARAMS_DS_CNT);
        cseg->fm_ce_se         = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
 
-       fill_progress_params_ctx(wqe->data, priv_tx);
+       fill_progress_params_ctx(wqe->tls_progress_params_ctx, priv_tx);
 }
 
 static void tx_fill_wi(struct mlx5e_txqsq *sq,
                       u16 pi, u8 num_wqebbs,
-                      skb_frag_t *resync_dump_frag)
+                      skb_frag_t *resync_dump_frag,
+                      u32 num_bytes)
 {
        struct mlx5e_tx_wqe_info *wi = &sq->db.wqe_info[pi];
 
        wi->skb              = NULL;
        wi->num_wqebbs       = num_wqebbs;
        wi->resync_dump_frag = resync_dump_frag;
+       wi->num_bytes        = num_bytes;
 }
 
 void mlx5e_ktls_tx_offload_set_pending(struct mlx5e_ktls_offload_context_tx *priv_tx)
@@ -143,7 +145,7 @@ post_static_params(struct mlx5e_txqsq *sq,
 
        umr_wqe = mlx5e_sq_fetch_wqe(sq, MLX5E_KTLS_STATIC_UMR_WQE_SZ, &pi);
        build_static_params(umr_wqe, sq->pc, sq->sqn, priv_tx, fence);
-       tx_fill_wi(sq, pi, MLX5E_KTLS_STATIC_WQEBBS, NULL);
+       tx_fill_wi(sq, pi, MLX5E_KTLS_STATIC_WQEBBS, NULL, 0);
        sq->pc += MLX5E_KTLS_STATIC_WQEBBS;
 }
 
@@ -157,7 +159,7 @@ post_progress_params(struct mlx5e_txqsq *sq,
 
        wqe = mlx5e_sq_fetch_wqe(sq, MLX5E_KTLS_PROGRESS_WQE_SZ, &pi);
        build_progress_params(wqe, sq->pc, sq->sqn, priv_tx, fence);
-       tx_fill_wi(sq, pi, MLX5E_KTLS_PROGRESS_WQEBBS, NULL);
+       tx_fill_wi(sq, pi, MLX5E_KTLS_PROGRESS_WQEBBS, NULL, 0);
        sq->pc += MLX5E_KTLS_PROGRESS_WQEBBS;
 }
 
@@ -248,43 +250,37 @@ tx_post_resync_params(struct mlx5e_txqsq *sq,
        mlx5e_ktls_tx_post_param_wqes(sq, priv_tx, skip_static_post, true);
 }
 
+struct mlx5e_dump_wqe {
+       struct mlx5_wqe_ctrl_seg ctrl;
+       struct mlx5_wqe_data_seg data;
+};
+
 static int
 tx_post_resync_dump(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                    skb_frag_t *frag, u32 tisn, bool first)
 {
        struct mlx5_wqe_ctrl_seg *cseg;
-       struct mlx5_wqe_eth_seg  *eseg;
        struct mlx5_wqe_data_seg *dseg;
-       struct mlx5e_tx_wqe *wqe;
+       struct mlx5e_dump_wqe *wqe;
        dma_addr_t dma_addr = 0;
-       u16 ds_cnt, ds_cnt_inl;
        u8  num_wqebbs;
-       u16 pi, ihs;
+       u16 ds_cnt;
        int fsz;
-
-       ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
-       ihs    = eth_get_headlen(skb->dev, skb->data, skb_headlen(skb));
-       ds_cnt_inl = DIV_ROUND_UP(ihs - INL_HDR_START_SZ, MLX5_SEND_WQE_DS);
-       ds_cnt += ds_cnt_inl;
-       ds_cnt += 1; /* one frag */
+       u16 pi;
 
        wqe = mlx5e_sq_fetch_wqe(sq, sizeof(*wqe), &pi);
 
+       ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
        num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
 
        cseg = &wqe->ctrl;
-       eseg = &wqe->eth;
-       dseg =  wqe->data;
+       dseg = &wqe->data;
 
        cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8)  | MLX5_OPCODE_DUMP);
        cseg->qpn_ds           = cpu_to_be32((sq->sqn << 8) | ds_cnt);
-       cseg->imm              = cpu_to_be32(tisn);
+       cseg->tisn             = cpu_to_be32(tisn << 8);
        cseg->fm_ce_se         = first ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
 
-       eseg->inline_hdr.sz = cpu_to_be16(ihs);
-       memcpy(eseg->inline_hdr.start, skb->data, ihs);
-       dseg += ds_cnt_inl;
-
        fsz = skb_frag_size(frag);
        dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
                                    DMA_TO_DEVICE);
@@ -296,7 +292,7 @@ tx_post_resync_dump(struct mlx5e_txqsq *sq, struct sk_buff *skb,
        dseg->byte_count = cpu_to_be32(fsz);
        mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
 
-       tx_fill_wi(sq, pi, num_wqebbs, frag);
+       tx_fill_wi(sq, pi, num_wqebbs, frag, fsz);
        sq->pc += num_wqebbs;
 
        WARN(num_wqebbs > MLX5E_KTLS_MAX_DUMP_WQEBBS,
@@ -323,7 +319,7 @@ static void tx_post_fence_nop(struct mlx5e_txqsq *sq)
        struct mlx5_wq_cyc *wq = &sq->wq;
        u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 
-       tx_fill_wi(sq, pi, 1, NULL);
+       tx_fill_wi(sq, pi, 1, NULL, 0);
 
        mlx5e_post_nop_fence(wq, sq->sqn, &sq->pc);
 }
@@ -434,7 +430,7 @@ struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
        priv_tx->expected_seq = seq + datalen;
 
        cseg = &(*wqe)->ctrl;
-       cseg->imm = cpu_to_be32(priv_tx->tisn);
+       cseg->tisn = cpu_to_be32(priv_tx->tisn << 8);
 
        stats->tls_encrypted_packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
        stats->tls_encrypted_bytes   += datalen;
index 8657e0f..2c75b27 100644 (file)
@@ -437,12 +437,6 @@ arfs_hash_bucket(struct arfs_table *arfs_t, __be16 src_port,
        return &arfs_t->rules_hash[bucket_idx];
 }
 
-static u8 arfs_get_ip_proto(const struct sk_buff *skb)
-{
-       return (skb->protocol == htons(ETH_P_IP)) ?
-               ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
-}
-
 static struct arfs_table *arfs_get_table(struct mlx5e_arfs_tables *arfs,
                                         u8 ip_proto, __be16 etype)
 {
@@ -602,31 +596,9 @@ out:
        arfs_may_expire_flow(priv);
 }
 
-/* return L4 destination port from ip4/6 packets */
-static __be16 arfs_get_dst_port(const struct sk_buff *skb)
-{
-       char *transport_header;
-
-       transport_header = skb_transport_header(skb);
-       if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
-               return ((struct tcphdr *)transport_header)->dest;
-       return ((struct udphdr *)transport_header)->dest;
-}
-
-/* return L4 source port from ip4/6 packets */
-static __be16 arfs_get_src_port(const struct sk_buff *skb)
-{
-       char *transport_header;
-
-       transport_header = skb_transport_header(skb);
-       if (arfs_get_ip_proto(skb) == IPPROTO_TCP)
-               return ((struct tcphdr *)transport_header)->source;
-       return ((struct udphdr *)transport_header)->source;
-}
-
 static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
                                         struct arfs_table *arfs_t,
-                                        const struct sk_buff *skb,
+                                        const struct flow_keys *fk,
                                         u16 rxq, u32 flow_id)
 {
        struct arfs_rule *rule;
@@ -641,19 +613,19 @@ static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
        INIT_WORK(&rule->arfs_work, arfs_handle_work);
 
        tuple = &rule->tuple;
-       tuple->etype = skb->protocol;
+       tuple->etype = fk->basic.n_proto;
+       tuple->ip_proto = fk->basic.ip_proto;
        if (tuple->etype == htons(ETH_P_IP)) {
-               tuple->src_ipv4 = ip_hdr(skb)->saddr;
-               tuple->dst_ipv4 = ip_hdr(skb)->daddr;
+               tuple->src_ipv4 = fk->addrs.v4addrs.src;
+               tuple->dst_ipv4 = fk->addrs.v4addrs.dst;
        } else {
-               memcpy(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
+               memcpy(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
                       sizeof(struct in6_addr));
-               memcpy(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
+               memcpy(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
                       sizeof(struct in6_addr));
        }
-       tuple->ip_proto = arfs_get_ip_proto(skb);
-       tuple->src_port = arfs_get_src_port(skb);
-       tuple->dst_port = arfs_get_dst_port(skb);
+       tuple->src_port = fk->ports.src;
+       tuple->dst_port = fk->ports.dst;
 
        rule->flow_id = flow_id;
        rule->filter_id = priv->fs.arfs.last_filter_id++ % RPS_NO_FILTER;
@@ -664,37 +636,33 @@ static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
        return rule;
 }
 
-static bool arfs_cmp_ips(struct arfs_tuple *tuple,
-                        const struct sk_buff *skb)
+static bool arfs_cmp(const struct arfs_tuple *tuple, const struct flow_keys *fk)
 {
-       if (tuple->etype == htons(ETH_P_IP) &&
-           tuple->src_ipv4 == ip_hdr(skb)->saddr &&
-           tuple->dst_ipv4 == ip_hdr(skb)->daddr)
-               return true;
-       if (tuple->etype == htons(ETH_P_IPV6) &&
-           (!memcmp(&tuple->src_ipv6, &ipv6_hdr(skb)->saddr,
-                    sizeof(struct in6_addr))) &&
-           (!memcmp(&tuple->dst_ipv6, &ipv6_hdr(skb)->daddr,
-                    sizeof(struct in6_addr))))
-               return true;
+       if (tuple->src_port != fk->ports.src || tuple->dst_port != fk->ports.dst)
+               return false;
+       if (tuple->etype != fk->basic.n_proto)
+               return false;
+       if (tuple->etype == htons(ETH_P_IP))
+               return tuple->src_ipv4 == fk->addrs.v4addrs.src &&
+                      tuple->dst_ipv4 == fk->addrs.v4addrs.dst;
+       if (tuple->etype == htons(ETH_P_IPV6))
+               return !memcmp(&tuple->src_ipv6, &fk->addrs.v6addrs.src,
+                              sizeof(struct in6_addr)) &&
+                      !memcmp(&tuple->dst_ipv6, &fk->addrs.v6addrs.dst,
+                              sizeof(struct in6_addr));
        return false;
 }
 
 static struct arfs_rule *arfs_find_rule(struct arfs_table *arfs_t,
-                                       const struct sk_buff *skb)
+                                       const struct flow_keys *fk)
 {
        struct arfs_rule *arfs_rule;
        struct hlist_head *head;
-       __be16 src_port = arfs_get_src_port(skb);
-       __be16 dst_port = arfs_get_dst_port(skb);
 
-       head = arfs_hash_bucket(arfs_t, src_port, dst_port);
+       head = arfs_hash_bucket(arfs_t, fk->ports.src, fk->ports.dst);
        hlist_for_each_entry(arfs_rule, head, hlist) {
-               if (arfs_rule->tuple.src_port == src_port &&
-                   arfs_rule->tuple.dst_port == dst_port &&
-                   arfs_cmp_ips(&arfs_rule->tuple, skb)) {
+               if (arfs_cmp(&arfs_rule->tuple, fk))
                        return arfs_rule;
-               }
        }
 
        return NULL;
@@ -707,20 +675,24 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
        struct mlx5e_arfs_tables *arfs = &priv->fs.arfs;
        struct arfs_table *arfs_t;
        struct arfs_rule *arfs_rule;
+       struct flow_keys fk;
+
+       if (!skb_flow_dissect_flow_keys(skb, &fk, 0))
+               return -EPROTONOSUPPORT;
 
-       if (skb->protocol != htons(ETH_P_IP) &&
-           skb->protocol != htons(ETH_P_IPV6))
+       if (fk.basic.n_proto != htons(ETH_P_IP) &&
+           fk.basic.n_proto != htons(ETH_P_IPV6))
                return -EPROTONOSUPPORT;
 
        if (skb->encapsulation)
                return -EPROTONOSUPPORT;
 
-       arfs_t = arfs_get_table(arfs, arfs_get_ip_proto(skb), skb->protocol);
+       arfs_t = arfs_get_table(arfs, fk.basic.ip_proto, fk.basic.n_proto);
        if (!arfs_t)
                return -EPROTONOSUPPORT;
 
        spin_lock_bh(&arfs->arfs_lock);
-       arfs_rule = arfs_find_rule(arfs_t, skb);
+       arfs_rule = arfs_find_rule(arfs_t, &fk);
        if (arfs_rule) {
                if (arfs_rule->rxq == rxq_index) {
                        spin_unlock_bh(&arfs->arfs_lock);
@@ -728,8 +700,7 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
                }
                arfs_rule->rxq = rxq_index;
        } else {
-               arfs_rule = arfs_alloc_rule(priv, arfs_t, skb,
-                                           rxq_index, flow_id);
+               arfs_rule = arfs_alloc_rule(priv, arfs_t, &fk, rxq_index, flow_id);
                if (!arfs_rule) {
                        spin_unlock_bh(&arfs->arfs_lock);
                        return -ENOMEM;
index 03bed71..20e628c 100644 (file)
@@ -1081,6 +1081,14 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
        link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) :
                mlx5e_port_speed2linkmodes(mdev, speed, !ext);
 
+       if ((link_modes & MLX5E_PROT_MASK(MLX5E_56GBASE_R4)) &&
+           autoneg != AUTONEG_ENABLE) {
+               netdev_err(priv->netdev, "%s: 56G link speed requires autoneg enabled\n",
+                          __func__);
+               err = -EINVAL;
+               goto out;
+       }
+
        link_modes = link_modes & eproto.cap;
        if (!link_modes) {
                netdev_err(priv->netdev, "%s: Not supported link mode(s) requested",
@@ -1338,6 +1346,9 @@ int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
        struct mlx5_core_dev *mdev = priv->mdev;
        int err;
 
+       if (!MLX5_CAP_GEN(mdev, vport_group_manager))
+               return -EOPNOTSUPP;
+
        if (pauseparam->autoneg)
                return -EINVAL;
 
@@ -1679,6 +1690,40 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev,
        return 0;
 }
 
+int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
+                              struct ethtool_flash *flash)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct net_device *dev = priv->netdev;
+       const struct firmware *fw;
+       int err;
+
+       if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
+               return -EOPNOTSUPP;
+
+       err = request_firmware_direct(&fw, flash->data, &dev->dev);
+       if (err)
+               return err;
+
+       dev_hold(dev);
+       rtnl_unlock();
+
+       err = mlx5_firmware_flash(mdev, fw, NULL);
+       release_firmware(fw);
+
+       rtnl_lock();
+       dev_put(dev);
+       return err;
+}
+
+static int mlx5e_flash_device(struct net_device *dev,
+                             struct ethtool_flash *flash)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+
+       return mlx5e_ethtool_flash_device(priv, flash);
+}
+
 static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable,
                                     bool is_rx_cq)
 {
@@ -1961,6 +2006,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .set_wol           = mlx5e_set_wol,
        .get_module_info   = mlx5e_get_module_info,
        .get_module_eeprom = mlx5e_get_module_eeprom,
+       .flash_device      = mlx5e_flash_device,
        .get_priv_flags    = mlx5e_get_priv_flags,
        .set_priv_flags    = mlx5e_set_priv_flags,
        .self_test         = mlx5e_self_test,
index 6c712c5..9d5f6e5 100644 (file)
@@ -1321,7 +1321,6 @@ err_free_txqsq:
 void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq)
 {
        sq->txq = netdev_get_tx_queue(sq->channel->netdev, sq->txq_ix);
-       clear_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state);
        set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
        netdev_tx_reset_queue(sq->txq);
        netif_tx_start_queue(sq->txq);
index 7ecfc53..00b2d4a 100644 (file)
@@ -1480,7 +1480,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
                              struct mlx5_flow_spec *spec,
                              struct flow_cls_offload *f,
                              struct net_device *filter_dev,
-                             u8 *match_level, u8 *tunnel_match_level)
+                             u8 *inner_match_level, u8 *outer_match_level)
 {
        struct netlink_ext_ack *extack = f->common.extack;
        void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
@@ -1495,8 +1495,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
        struct flow_dissector *dissector = rule->match.dissector;
        u16 addr_type = 0;
        u8 ip_proto = 0;
+       u8 *match_level;
 
-       *match_level = MLX5_MATCH_NONE;
+       match_level = outer_match_level;
 
        if (dissector->used_keys &
            ~(BIT(FLOW_DISSECTOR_KEY_META) |
@@ -1524,12 +1525,14 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
        }
 
        if (mlx5e_get_tc_tun(filter_dev)) {
-               if (parse_tunnel_attr(priv, spec, f, filter_dev, tunnel_match_level))
+               if (parse_tunnel_attr(priv, spec, f, filter_dev,
+                                     outer_match_level))
                        return -EOPNOTSUPP;
 
-               /* In decap flow, header pointers should point to the inner
+               /* At this point, header pointers should point to the inner
                 * headers, outer header were already set by parse_tunnel_attr
                 */
+               match_level = inner_match_level;
                headers_c = get_match_headers_criteria(MLX5_FLOW_CONTEXT_ACTION_DECAP,
                                                       spec);
                headers_v = get_match_headers_value(MLX5_FLOW_CONTEXT_ACTION_DECAP,
@@ -1831,35 +1834,41 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
                            struct flow_cls_offload *f,
                            struct net_device *filter_dev)
 {
+       u8 inner_match_level, outer_match_level, non_tunnel_match_level;
        struct netlink_ext_ack *extack = f->common.extack;
        struct mlx5_core_dev *dev = priv->mdev;
        struct mlx5_eswitch *esw = dev->priv.eswitch;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
-       u8 match_level, tunnel_match_level = MLX5_MATCH_NONE;
        struct mlx5_eswitch_rep *rep;
        int err;
 
-       err = __parse_cls_flower(priv, spec, f, filter_dev, &match_level, &tunnel_match_level);
+       inner_match_level = MLX5_MATCH_NONE;
+       outer_match_level = MLX5_MATCH_NONE;
+
+       err = __parse_cls_flower(priv, spec, f, filter_dev, &inner_match_level,
+                                &outer_match_level);
+       non_tunnel_match_level = (inner_match_level == MLX5_MATCH_NONE) ?
+                                outer_match_level : inner_match_level;
 
        if (!err && (flow->flags & MLX5E_TC_FLOW_ESWITCH)) {
                rep = rpriv->rep;
                if (rep->vport != MLX5_VPORT_UPLINK &&
                    (esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE &&
-                   esw->offloads.inline_mode < match_level)) {
+                   esw->offloads.inline_mode < non_tunnel_match_level)) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Flow is not offloaded due to min inline setting");
                        netdev_warn(priv->netdev,
                                    "Flow is not offloaded due to min inline setting, required %d actual %d\n",
-                                   match_level, esw->offloads.inline_mode);
+                                   non_tunnel_match_level, esw->offloads.inline_mode);
                        return -EOPNOTSUPP;
                }
        }
 
        if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
-               flow->esw_attr->match_level = match_level;
-               flow->esw_attr->tunnel_match_level = tunnel_match_level;
+               flow->esw_attr->inner_match_level = inner_match_level;
+               flow->esw_attr->outer_match_level = outer_match_level;
        } else {
-               flow->nic_attr->match_level = match_level;
+               flow->nic_attr->match_level = non_tunnel_match_level;
        }
 
        return err;
@@ -3158,7 +3167,7 @@ mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
 
        esw_attr->parse_attr = parse_attr;
        esw_attr->chain = f->common.chain_index;
-       esw_attr->prio = TC_H_MAJ(f->common.prio) >> 16;
+       esw_attr->prio = f->common.prio;
 
        esw_attr->in_rep = in_rep;
        esw_attr->in_mdev = in_mdev;
index a38e8a3..04685db 100644 (file)
@@ -377,8 +377,8 @@ struct mlx5_esw_flow_attr {
                struct mlx5_termtbl_handle *termtbl;
        } dests[MLX5_MAX_FLOW_FWD_VPORTS];
        u32     mod_hdr_id;
-       u8      match_level;
-       u8      tunnel_match_level;
+       u8      inner_match_level;
+       u8      outer_match_level;
        struct mlx5_fc *counter;
        u32     chain;
        u16     prio;
index 089ae4d..0323fd0 100644 (file)
@@ -207,14 +207,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
 
        mlx5_eswitch_set_rule_source_port(esw, spec, attr);
 
-       if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
-               if (attr->tunnel_match_level != MLX5_MATCH_NONE)
-                       spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
-               if (attr->match_level != MLX5_MATCH_NONE)
-                       spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
-       } else if (attr->match_level != MLX5_MATCH_NONE) {
+       if (attr->outer_match_level != MLX5_MATCH_NONE)
                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
-       }
+       if (attr->inner_match_level != MLX5_MATCH_NONE)
+               spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
 
        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
                flow_act.modify_id = attr->mod_hdr_id;
@@ -290,7 +286,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
        mlx5_eswitch_set_rule_source_port(esw, spec, attr);
 
        spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
-       if (attr->match_level != MLX5_MATCH_NONE)
+       if (attr->outer_match_level != MLX5_MATCH_NONE)
                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 
        rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
index 9314777..d685122 100644 (file)
@@ -590,7 +590,8 @@ mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
                        data_size = crdump_size - offset;
                else
                        data_size = MLX5_CR_DUMP_CHUNK_SIZE;
-               err = devlink_fmsg_binary_put(fmsg, cr_data, data_size);
+               err = devlink_fmsg_binary_put(fmsg, (char *)cr_data + offset,
+                                             data_size);
                if (err)
                        goto free_data;
        }
@@ -700,6 +701,16 @@ static void poll_health(struct timer_list *t)
        if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
                goto out;
 
+       fatal_error = check_fatal_sensors(dev);
+
+       if (fatal_error && !health->fatal_error) {
+               mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
+               dev->priv.health.fatal_error = fatal_error;
+               print_health_info(dev);
+               mlx5_trigger_health_work(dev);
+               goto out;
+       }
+
        count = ioread32be(health->health_counter);
        if (count == health->prev)
                ++health->miss_counter;
@@ -718,15 +729,6 @@ static void poll_health(struct timer_list *t)
        if (health->synd && health->synd != prev_synd)
                queue_work(health->wq, &health->report_work);
 
-       fatal_error = check_fatal_sensors(dev);
-
-       if (fatal_error && !health->fatal_error) {
-               mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
-               dev->priv.health.fatal_error = fatal_error;
-               print_health_info(dev);
-               mlx5_trigger_health_work(dev);
-       }
-
 out:
        mod_timer(&health->timer, get_next_poll_jiffies());
 }
index ebd81f6..90cb50f 100644 (file)
@@ -122,6 +122,14 @@ static int mlx5i_get_ts_info(struct net_device *netdev,
        return mlx5e_ethtool_get_ts_info(priv, info);
 }
 
+static int mlx5i_flash_device(struct net_device *netdev,
+                             struct ethtool_flash *flash)
+{
+       struct mlx5e_priv *priv = mlx5i_epriv(netdev);
+
+       return mlx5e_ethtool_flash_device(priv, flash);
+}
+
 enum mlx5_ptys_width {
        MLX5_PTYS_WIDTH_1X      = 1 << 0,
        MLX5_PTYS_WIDTH_2X      = 1 << 1,
@@ -233,6 +241,7 @@ const struct ethtool_ops mlx5i_ethtool_ops = {
        .get_ethtool_stats  = mlx5i_get_ethtool_stats,
        .get_ringparam      = mlx5i_get_ringparam,
        .set_ringparam      = mlx5i_set_ringparam,
+       .flash_device       = mlx5i_flash_device,
        .get_channels       = mlx5i_get_channels,
        .set_channels       = mlx5i_set_channels,
        .get_coalesce       = mlx5i_get_coalesce,
index ea9ee88..ea1d4d2 100644 (file)
@@ -27,6 +27,7 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
        case 128:
                general_obj_key_size =
                        MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128;
+               key_p += sz_bytes;
                break;
        case 256:
                general_obj_key_size =
index e8ac905..84a87d0 100644 (file)
@@ -471,7 +471,7 @@ int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei)
 void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
                                 unsigned int priority)
 {
-       rulei->priority = priority >> 16;
+       rulei->priority = priority;
 }
 
 void mlxsw_sp_acl_rulei_keymask_u32(struct mlxsw_sp_acl_rule_info *rulei,
index 63b07ed..38bb1cf 100644 (file)
@@ -29,7 +29,7 @@
 
 struct mlxsw_sp_ptp_state {
        struct mlxsw_sp *mlxsw_sp;
-       struct rhashtable unmatched_ht;
+       struct rhltable unmatched_ht;
        spinlock_t unmatched_lock; /* protects the HT */
        struct delayed_work ht_gc_dw;
        u32 gc_cycle;
@@ -45,7 +45,7 @@ struct mlxsw_sp1_ptp_key {
 
 struct mlxsw_sp1_ptp_unmatched {
        struct mlxsw_sp1_ptp_key key;
-       struct rhash_head ht_node;
+       struct rhlist_head ht_node;
        struct rcu_head rcu;
        struct sk_buff *skb;
        u64 timestamp;
@@ -359,7 +359,7 @@ static int mlxsw_sp_ptp_parse(struct sk_buff *skb,
 /* Returns NULL on successful insertion, a pointer on conflict, or an ERR_PTR on
  * error.
  */
-static struct mlxsw_sp1_ptp_unmatched *
+static int
 mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
                             struct mlxsw_sp1_ptp_key key,
                             struct sk_buff *skb,
@@ -368,41 +368,51 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
        int cycles = MLXSW_SP1_PTP_HT_GC_TIMEOUT / MLXSW_SP1_PTP_HT_GC_INTERVAL;
        struct mlxsw_sp_ptp_state *ptp_state = mlxsw_sp->ptp_state;
        struct mlxsw_sp1_ptp_unmatched *unmatched;
-       struct mlxsw_sp1_ptp_unmatched *conflict;
+       int err;
 
        unmatched = kzalloc(sizeof(*unmatched), GFP_ATOMIC);
        if (!unmatched)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        unmatched->key = key;
        unmatched->skb = skb;
        unmatched->timestamp = timestamp;
        unmatched->gc_cycle = mlxsw_sp->ptp_state->gc_cycle + cycles;
 
-       conflict = rhashtable_lookup_get_insert_fast(&ptp_state->unmatched_ht,
-                                           &unmatched->ht_node,
-                                           mlxsw_sp1_ptp_unmatched_ht_params);
-       if (conflict)
+       err = rhltable_insert(&ptp_state->unmatched_ht, &unmatched->ht_node,
+                             mlxsw_sp1_ptp_unmatched_ht_params);
+       if (err)
                kfree(unmatched);
 
-       return conflict;
+       return err;
 }
 
 static struct mlxsw_sp1_ptp_unmatched *
 mlxsw_sp1_ptp_unmatched_lookup(struct mlxsw_sp *mlxsw_sp,
-                              struct mlxsw_sp1_ptp_key key)
+                              struct mlxsw_sp1_ptp_key key, int *p_length)
 {
-       return rhashtable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key,
-                                mlxsw_sp1_ptp_unmatched_ht_params);
+       struct mlxsw_sp1_ptp_unmatched *unmatched, *last = NULL;
+       struct rhlist_head *tmp, *list;
+       int length = 0;
+
+       list = rhltable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key,
+                              mlxsw_sp1_ptp_unmatched_ht_params);
+       rhl_for_each_entry_rcu(unmatched, tmp, list, ht_node) {
+               last = unmatched;
+               length++;
+       }
+
+       *p_length = length;
+       return last;
 }
 
 static int
 mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp1_ptp_unmatched *unmatched)
 {
-       return rhashtable_remove_fast(&mlxsw_sp->ptp_state->unmatched_ht,
-                                     &unmatched->ht_node,
-                                     mlxsw_sp1_ptp_unmatched_ht_params);
+       return rhltable_remove(&mlxsw_sp->ptp_state->unmatched_ht,
+                              &unmatched->ht_node,
+                              mlxsw_sp1_ptp_unmatched_ht_params);
 }
 
 /* This function is called in the following scenarios:
@@ -489,75 +499,38 @@ static void mlxsw_sp1_ptp_got_piece(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp1_ptp_key key,
                                    struct sk_buff *skb, u64 timestamp)
 {
-       struct mlxsw_sp1_ptp_unmatched *unmatched, *conflict;
+       struct mlxsw_sp1_ptp_unmatched *unmatched;
+       int length;
        int err;
 
        rcu_read_lock();
 
-       unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key);
-
        spin_lock(&mlxsw_sp->ptp_state->unmatched_lock);
 
-       if (unmatched) {
-               /* There was an unmatched entry when we looked, but it may have
-                * been removed before we took the lock.
-                */
-               err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp, unmatched);
-               if (err)
-                       unmatched = NULL;
-       }
-
-       if (!unmatched) {
-               /* We have no unmatched entry, but one may have been added after
-                * we looked, but before we took the lock.
-                */
-               unmatched = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
-                                                        skb, timestamp);
-               if (IS_ERR(unmatched)) {
-                       if (skb)
-                               mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
-                                                           key.local_port,
-                                                           key.ingress, NULL);
-                       unmatched = NULL;
-               } else if (unmatched) {
-                       /* Save just told us, under lock, that the entry is
-                        * there, so this has to work.
-                        */
-                       err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp,
-                                                            unmatched);
-                       WARN_ON_ONCE(err);
-               }
-       }
-
-       /* If unmatched is non-NULL here, it comes either from the lookup, or
-        * from the save attempt above. In either case the entry was removed
-        * from the hash table. If unmatched is NULL, a new unmatched entry was
-        * added to the hash table, and there was no conflict.
-        */
-
+       unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key, &length);
        if (skb && unmatched && unmatched->timestamp) {
                unmatched->skb = skb;
        } else if (timestamp && unmatched && unmatched->skb) {
                unmatched->timestamp = timestamp;
-       } else if (unmatched) {
-               /* unmatched holds an older entry of the same type: either an
-                * skb if we are handling skb, or a timestamp if we are handling
-                * timestamp. We can't match that up, so save what we have.
+       } else {
+               /* Either there is no entry to match, or one that is there is
+                * incompatible.
                 */
-               conflict = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
-                                                       skb, timestamp);
-               if (IS_ERR(conflict)) {
-                       if (skb)
-                               mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
-                                                           key.local_port,
-                                                           key.ingress, NULL);
-               } else {
-                       /* Above, we removed an object with this key from the
-                        * hash table, under lock, so conflict can not be a
-                        * valid pointer.
-                        */
-                       WARN_ON_ONCE(conflict);
-               }
+               if (length < 100)
+                       err = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
+                                                          skb, timestamp);
+               else
+                       err = -E2BIG;
+               if (err && skb)
+                       mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
+                                                   key.local_port,
+                                                   key.ingress, NULL);
+               unmatched = NULL;
+       }
+
+       if (unmatched) {
+               err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp, unmatched);
+               WARN_ON_ONCE(err);
        }
 
        spin_unlock(&mlxsw_sp->ptp_state->unmatched_lock);
@@ -669,9 +642,8 @@ mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state,
        local_bh_disable();
 
        spin_lock(&ptp_state->unmatched_lock);
-       err = rhashtable_remove_fast(&ptp_state->unmatched_ht,
-                                    &unmatched->ht_node,
-                                    mlxsw_sp1_ptp_unmatched_ht_params);
+       err = rhltable_remove(&ptp_state->unmatched_ht, &unmatched->ht_node,
+                             mlxsw_sp1_ptp_unmatched_ht_params);
        spin_unlock(&ptp_state->unmatched_lock);
 
        if (err)
@@ -702,7 +674,7 @@ static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work)
        ptp_state = container_of(dwork, struct mlxsw_sp_ptp_state, ht_gc_dw);
        gc_cycle = ptp_state->gc_cycle++;
 
-       rhashtable_walk_enter(&ptp_state->unmatched_ht, &iter);
+       rhltable_walk_enter(&ptp_state->unmatched_ht, &iter);
        rhashtable_walk_start(&iter);
        while ((obj = rhashtable_walk_next(&iter))) {
                if (IS_ERR(obj))
@@ -855,8 +827,8 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 
        spin_lock_init(&ptp_state->unmatched_lock);
 
-       err = rhashtable_init(&ptp_state->unmatched_ht,
-                             &mlxsw_sp1_ptp_unmatched_ht_params);
+       err = rhltable_init(&ptp_state->unmatched_ht,
+                           &mlxsw_sp1_ptp_unmatched_ht_params);
        if (err)
                goto err_hashtable_init;
 
@@ -891,7 +863,7 @@ err_fifo_clr:
 err_mtptpt1_set:
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
 err_mtptpt_set:
-       rhashtable_destroy(&ptp_state->unmatched_ht);
+       rhltable_destroy(&ptp_state->unmatched_ht);
 err_hashtable_init:
        kfree(ptp_state);
        return ERR_PTR(err);
@@ -906,8 +878,8 @@ void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
        mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, false);
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
        mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
-       rhashtable_free_and_destroy(&ptp_state->unmatched_ht,
-                                   &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
+       rhltable_free_and_destroy(&ptp_state->unmatched_ht,
+                                 &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
        kfree(ptp_state);
 }
 
index 39aca1a..86fc6e6 100644 (file)
@@ -317,7 +317,7 @@ static void is2_action_set(struct vcap_data *data,
                break;
        case OCELOT_ACL_ACTION_TRAP:
                VCAP_ACT_SET(PORT_MASK, 0x0);
-               VCAP_ACT_SET(MASK_MODE, 0x0);
+               VCAP_ACT_SET(MASK_MODE, 0x1);
                VCAP_ACT_SET(POLICE_ENA, 0x0);
                VCAP_ACT_SET(POLICE_IDX, 0x0);
                VCAP_ACT_SET(CPU_QU_NUM, 0x0);
index 59487d4..b894bc0 100644 (file)
@@ -13,12 +13,6 @@ struct ocelot_port_block {
        struct ocelot_port *port;
 };
 
-static u16 get_prio(u32 prio)
-{
-       /* prio starts from 0x1000 while the ids starts from 0 */
-       return prio >> 16;
-}
-
 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
                                      struct ocelot_ace_rule *rule)
 {
@@ -168,7 +162,7 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
        }
 
 finished_key_parsing:
-       ocelot_rule->prio = get_prio(f->common.prio);
+       ocelot_rule->prio = f->common.prio;
        ocelot_rule->id = f->cookie;
        return ocelot_flower_parse_action(f, ocelot_rule);
 }
@@ -218,7 +212,7 @@ static int ocelot_flower_destroy(struct flow_cls_offload *f,
        struct ocelot_ace_rule rule;
        int ret;
 
-       rule.prio = get_prio(f->common.prio);
+       rule.prio = f->common.prio;
        rule.port = port_block->port;
        rule.id = f->cookie;
 
@@ -236,7 +230,7 @@ static int ocelot_flower_stats_update(struct flow_cls_offload *f,
        struct ocelot_ace_rule rule;
        int ret;
 
-       rule.prio = get_prio(f->common.prio);
+       rule.prio = f->common.prio;
        rule.port = port_block->port;
        rule.id = f->cookie;
        ret = ocelot_ace_rule_stats_update(&rule);
index d8b7fba..337b0cb 100644 (file)
@@ -3919,7 +3919,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * setup (if available). */
        status = myri10ge_request_irq(mgp);
        if (status != 0)
-               goto abort_with_firmware;
+               goto abort_with_slices;
        myri10ge_free_irq(mgp);
 
        /* Save configuration space to be restored if the
index d0a01e8..b339125 100644 (file)
@@ -232,9 +232,9 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
        if (!laddr) {
-               printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
-               dev_kfree_skb(skb);
-               return NETDEV_TX_BUSY;
+               pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name);
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
        }
 
        sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0);       /* clear status */
index 4054b70..5afcb3c 100644 (file)
@@ -1163,7 +1163,7 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
             bool clr_gpr, lmem_step step)
 {
        s32 off = nfp_prog->stack_frame_depth + meta->insn.off + ptr_off;
-       bool first = true, last;
+       bool first = true, narrow_ld, last;
        bool needs_inc = false;
        swreg stack_off_reg;
        u8 prev_gpr = 255;
@@ -1209,13 +1209,22 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
 
                needs_inc = true;
        }
+
+       narrow_ld = clr_gpr && size < 8;
+
        if (lm3) {
+               unsigned int nop_cnt;
+
                emit_csr_wr(nfp_prog, imm_b(nfp_prog), NFP_CSR_ACT_LM_ADDR3);
-               /* For size < 4 one slot will be filled by zeroing of upper. */
-               wrp_nops(nfp_prog, clr_gpr && size < 8 ? 2 : 3);
+               /* For size < 4 one slot will be filled by zeroing of upper,
+                * but be careful, that zeroing could be eliminated by zext
+                * optimization.
+                */
+               nop_cnt = narrow_ld && meta->flags & FLAG_INSN_DO_ZEXT ? 2 : 3;
+               wrp_nops(nfp_prog, nop_cnt);
        }
 
-       if (clr_gpr && size < 8)
+       if (narrow_ld)
                wrp_zext(nfp_prog, meta, gpr);
 
        while (size) {
index d5bbe3d..05981b5 100644 (file)
@@ -260,9 +260,6 @@ nfp_flower_cmsg_process_one_rx(struct nfp_app *app, struct sk_buff *skb)
 
        type = cmsg_hdr->type;
        switch (type) {
-       case NFP_FLOWER_CMSG_TYPE_PORT_REIFY:
-               nfp_flower_cmsg_portreify_rx(app, skb);
-               break;
        case NFP_FLOWER_CMSG_TYPE_PORT_MOD:
                nfp_flower_cmsg_portmod_rx(app, skb);
                break;
@@ -328,8 +325,7 @@ nfp_flower_queue_ctl_msg(struct nfp_app *app, struct sk_buff *skb, int type)
        struct nfp_flower_priv *priv = app->priv;
        struct sk_buff_head *skb_head;
 
-       if (type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY ||
-           type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
+       if (type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
                skb_head = &priv->cmsg_skbs_high;
        else
                skb_head = &priv->cmsg_skbs_low;
@@ -368,6 +364,10 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
        } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH) {
                /* Acks from the NFP that the route is added - ignore. */
                dev_consume_skb_any(skb);
+       } else if (cmsg_hdr->type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY) {
+               /* Handle REIFY acks outside wq to prevent RTNL conflict. */
+               nfp_flower_cmsg_portreify_rx(app, skb);
+               dev_consume_skb_any(skb);
        } else {
                nfp_flower_queue_ctl_msg(app, skb, cmsg_hdr->type);
        }
index e209f15..457bdc6 100644 (file)
@@ -1409,13 +1409,21 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
        struct nfp_flower_priv *priv = app->priv;
        struct flow_block_cb *block_cb;
 
-       if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
-           !(f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
-             nfp_flower_internal_port_can_offload(app, netdev)))
+       if ((f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
+            !nfp_flower_internal_port_can_offload(app, netdev)) ||
+           (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
+            nfp_flower_internal_port_can_offload(app, netdev)))
                return -EOPNOTSUPP;
 
        switch (f->command) {
        case FLOW_BLOCK_BIND:
+               cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
+               if (cb_priv &&
+                   flow_block_cb_is_busy(nfp_flower_setup_indr_block_cb,
+                                         cb_priv,
+                                         &nfp_block_cb_list))
+                       return -EBUSY;
+
                cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
                if (!cb_priv)
                        return -ENOMEM;
index 86e968c..124a43d 100644 (file)
@@ -93,7 +93,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
                return -EOPNOTSUPP;
        }
 
-       if (flow->common.prio != (1 << 16)) {
+       if (flow->common.prio != 1) {
                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires highest priority");
                return -EOPNOTSUPP;
        }
index a7a80f4..f0ee982 100644 (file)
@@ -328,13 +328,13 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
        flow.daddr = *(__be32 *)n->primary_key;
 
-       /* Only concerned with route changes for representors. */
-       if (!nfp_netdev_is_nfp_repr(n->dev))
-               return NOTIFY_DONE;
-
        app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
        app = app_priv->app;
 
+       if (!nfp_netdev_is_nfp_repr(n->dev) &&
+           !nfp_flower_internal_port_can_offload(app, n->dev))
+               return NOTIFY_DONE;
+
        /* Only concerned with changes to routes already added to NFP. */
        if (!nfp_tun_has_route(app, flow.daddr))
                return NOTIFY_DONE;
index b327b29..a6b4bfa 100644 (file)
@@ -713,6 +713,21 @@ struct nv_skb_map {
        struct nv_skb_map *next_tx_ctx;
 };
 
+struct nv_txrx_stats {
+       u64 stat_rx_packets;
+       u64 stat_rx_bytes; /* not always available in HW */
+       u64 stat_rx_missed_errors;
+       u64 stat_rx_dropped;
+       u64 stat_tx_packets; /* not always available in HW */
+       u64 stat_tx_bytes;
+       u64 stat_tx_dropped;
+};
+
+#define nv_txrx_stats_inc(member) \
+               __this_cpu_inc(np->txrx_stats->member)
+#define nv_txrx_stats_add(member, count) \
+               __this_cpu_add(np->txrx_stats->member, (count))
+
 /*
  * SMP locking:
  * All hardware access under netdev_priv(dev)->lock, except the performance
@@ -797,10 +812,7 @@ struct fe_priv {
 
        /* RX software stats */
        struct u64_stats_sync swstats_rx_syncp;
-       u64 stat_rx_packets;
-       u64 stat_rx_bytes; /* not always available in HW */
-       u64 stat_rx_missed_errors;
-       u64 stat_rx_dropped;
+       struct nv_txrx_stats __percpu *txrx_stats;
 
        /* media detection workaround.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
@@ -826,9 +838,6 @@ struct fe_priv {
 
        /* TX software stats */
        struct u64_stats_sync swstats_tx_syncp;
-       u64 stat_tx_packets; /* not always available in HW */
-       u64 stat_tx_bytes;
-       u64 stat_tx_dropped;
 
        /* msi/msi-x fields */
        u32 msi_flags;
@@ -1721,6 +1730,39 @@ static void nv_update_stats(struct net_device *dev)
        }
 }
 
+static void nv_get_stats(int cpu, struct fe_priv *np,
+                        struct rtnl_link_stats64 *storage)
+{
+       struct nv_txrx_stats *src = per_cpu_ptr(np->txrx_stats, cpu);
+       unsigned int syncp_start;
+       u64 rx_packets, rx_bytes, rx_dropped, rx_missed_errors;
+       u64 tx_packets, tx_bytes, tx_dropped;
+
+       do {
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
+               rx_packets       = src->stat_rx_packets;
+               rx_bytes         = src->stat_rx_bytes;
+               rx_dropped       = src->stat_rx_dropped;
+               rx_missed_errors = src->stat_rx_missed_errors;
+       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
+
+       storage->rx_packets       += rx_packets;
+       storage->rx_bytes         += rx_bytes;
+       storage->rx_dropped       += rx_dropped;
+       storage->rx_missed_errors += rx_missed_errors;
+
+       do {
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
+               tx_packets  = src->stat_tx_packets;
+               tx_bytes    = src->stat_tx_bytes;
+               tx_dropped  = src->stat_tx_dropped;
+       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
+
+       storage->tx_packets += tx_packets;
+       storage->tx_bytes   += tx_bytes;
+       storage->tx_dropped += tx_dropped;
+}
+
 /*
  * nv_get_stats64: dev->ndo_get_stats64 function
  * Get latest stats value from the nic.
@@ -1733,7 +1775,7 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
        __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
-       unsigned int syncp_start;
+       int cpu;
 
        /*
         * Note: because HW stats are not always available and for
@@ -1746,20 +1788,8 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
         */
 
        /* software stats */
-       do {
-               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
-               storage->rx_packets       = np->stat_rx_packets;
-               storage->rx_bytes         = np->stat_rx_bytes;
-               storage->rx_dropped       = np->stat_rx_dropped;
-               storage->rx_missed_errors = np->stat_rx_missed_errors;
-       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
-
-       do {
-               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
-               storage->tx_packets = np->stat_tx_packets;
-               storage->tx_bytes   = np->stat_tx_bytes;
-               storage->tx_dropped = np->stat_tx_dropped;
-       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
+       for_each_online_cpu(cpu)
+               nv_get_stats(cpu, np, storage);
 
        /* If the nic supports hw counters then retrieve latest values */
        if (np->driver_data & DEV_HAS_STATISTICS_V123) {
@@ -1827,7 +1857,7 @@ static int nv_alloc_rx(struct net_device *dev)
                } else {
 packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_dropped++;
+                       nv_txrx_stats_inc(stat_rx_dropped);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
                }
@@ -1869,7 +1899,7 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                } else {
 packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_dropped++;
+                       nv_txrx_stats_inc(stat_rx_dropped);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
                }
@@ -2013,7 +2043,7 @@ static void nv_drain_tx(struct net_device *dev)
                }
                if (nv_release_txskb(np, &np->tx_skb[i])) {
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                }
                np->tx_skb[i].dma = 0;
@@ -2227,7 +2257,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* on DMA mapping error - drop the packet */
                        dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                        return NETDEV_TX_OK;
                }
@@ -2273,7 +2303,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_dropped++;
+                               nv_txrx_stats_inc(stat_tx_dropped);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                                return NETDEV_TX_OK;
                        }
@@ -2384,7 +2414,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                        /* on DMA mapping error - drop the packet */
                        dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                       np->stat_tx_dropped++;
+                       nv_txrx_stats_inc(stat_tx_dropped);
                        u64_stats_update_end(&np->swstats_tx_syncp);
                        return NETDEV_TX_OK;
                }
@@ -2431,7 +2461,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                                dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_dropped++;
+                               nv_txrx_stats_inc(stat_tx_dropped);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                                return NETDEV_TX_OK;
                        }
@@ -2560,9 +2590,12 @@ static int nv_tx_done(struct net_device *dev, int limit)
                                            && !(flags & NV_TX_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
+                                       unsigned int len;
+
                                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                                       np->stat_tx_packets++;
-                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_inc(stat_tx_packets);
+                                       len = np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_add(stat_tx_bytes, len);
                                        u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                bytes_compl += np->get_tx_ctx->skb->len;
@@ -2577,9 +2610,12 @@ static int nv_tx_done(struct net_device *dev, int limit)
                                            && !(flags & NV_TX2_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
+                                       unsigned int len;
+
                                        u64_stats_update_begin(&np->swstats_tx_syncp);
-                                       np->stat_tx_packets++;
-                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_inc(stat_tx_packets);
+                                       len = np->get_tx_ctx->skb->len;
+                                       nv_txrx_stats_add(stat_tx_bytes, len);
                                        u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                bytes_compl += np->get_tx_ctx->skb->len;
@@ -2627,9 +2663,12 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
                                                nv_legacybackoff_reseed(dev);
                                }
                        } else {
+                               unsigned int len;
+
                                u64_stats_update_begin(&np->swstats_tx_syncp);
-                               np->stat_tx_packets++;
-                               np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                               nv_txrx_stats_inc(stat_tx_packets);
+                               len = np->get_tx_ctx->skb->len;
+                               nv_txrx_stats_add(stat_tx_bytes, len);
                                u64_stats_update_end(&np->swstats_tx_syncp);
                        }
 
@@ -2806,6 +2845,15 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
        }
 }
 
+static void rx_missing_handler(u32 flags, struct fe_priv *np)
+{
+       if (flags & NV_RX_MISSEDFRAME) {
+               u64_stats_update_begin(&np->swstats_rx_syncp);
+               nv_txrx_stats_inc(stat_rx_missed_errors);
+               u64_stats_update_end(&np->swstats_rx_syncp);
+       }
+}
+
 static int nv_rx_process(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
@@ -2848,11 +2896,7 @@ static int nv_rx_process(struct net_device *dev, int limit)
                                        }
                                        /* the rest are hard errors */
                                        else {
-                                               if (flags & NV_RX_MISSEDFRAME) {
-                                                       u64_stats_update_begin(&np->swstats_rx_syncp);
-                                                       np->stat_rx_missed_errors++;
-                                                       u64_stats_update_end(&np->swstats_rx_syncp);
-                                               }
+                                               rx_missing_handler(flags, np);
                                                dev_kfree_skb(skb);
                                                goto next_pkt;
                                        }
@@ -2896,8 +2940,8 @@ static int nv_rx_process(struct net_device *dev, int limit)
                skb->protocol = eth_type_trans(skb, dev);
                napi_gro_receive(&np->napi, skb);
                u64_stats_update_begin(&np->swstats_rx_syncp);
-               np->stat_rx_packets++;
-               np->stat_rx_bytes += len;
+               nv_txrx_stats_inc(stat_rx_packets);
+               nv_txrx_stats_add(stat_rx_bytes, len);
                u64_stats_update_end(&np->swstats_rx_syncp);
 next_pkt:
                if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
@@ -2982,8 +3026,8 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                        }
                        napi_gro_receive(&np->napi, skb);
                        u64_stats_update_begin(&np->swstats_rx_syncp);
-                       np->stat_rx_packets++;
-                       np->stat_rx_bytes += len;
+                       nv_txrx_stats_inc(stat_rx_packets);
+                       nv_txrx_stats_add(stat_rx_bytes, len);
                        u64_stats_update_end(&np->swstats_rx_syncp);
                } else {
                        dev_kfree_skb(skb);
@@ -5651,6 +5695,12 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        SET_NETDEV_DEV(dev, &pci_dev->dev);
        u64_stats_init(&np->swstats_rx_syncp);
        u64_stats_init(&np->swstats_tx_syncp);
+       np->txrx_stats = alloc_percpu(struct nv_txrx_stats);
+       if (!np->txrx_stats) {
+               pr_err("np->txrx_stats, alloc memory error.\n");
+               err = -ENOMEM;
+               goto out_alloc_percpu;
+       }
 
        timer_setup(&np->oom_kick, nv_do_rx_refill, 0);
        timer_setup(&np->nic_poll, nv_do_nic_poll, 0);
@@ -6060,6 +6110,8 @@ out_relreg:
 out_disable:
        pci_disable_device(pci_dev);
 out_free:
+       free_percpu(np->txrx_stats);
+out_alloc_percpu:
        free_netdev(dev);
 out:
        return err;
@@ -6105,6 +6157,9 @@ static void nv_restore_mac_addr(struct pci_dev *pci_dev)
 static void nv_remove(struct pci_dev *pci_dev)
 {
        struct net_device *dev = pci_get_drvdata(pci_dev);
+       struct fe_priv *np = netdev_priv(dev);
+
+       free_percpu(np->txrx_stats);
 
        unregister_netdev(dev);
 
index 829dd60..1efff7f 100644 (file)
@@ -1325,7 +1325,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                                              &drv_version);
                if (rc) {
                        DP_NOTICE(cdev, "Failed sending drv version command\n");
-                       return rc;
+                       goto err4;
                }
        }
 
@@ -1333,6 +1333,8 @@ static int qed_slowpath_start(struct qed_dev *cdev,
 
        return 0;
 
+err4:
+       qed_ll2_dealloc_if(cdev);
 err3:
        qed_hw_stop(cdev);
 err2:
index e1dd6ea..bae0074 100644 (file)
@@ -5921,6 +5921,7 @@ static struct sk_buff *rtl8169_try_rx_copy(void *data,
        skb = napi_alloc_skb(&tp->napi, pkt_size);
        if (skb)
                skb_copy_to_linear_data(skb, data, pkt_size);
+       dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
 
        return skb;
 }
index ef8f089..6cacd5e 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Renesas Ethernet AVB device driver
  *
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2019 Renesas Electronics Corporation
  * Copyright (C) 2015 Renesas Solutions Corp.
  * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
  *
@@ -513,7 +513,10 @@ static void ravb_get_tx_tstamp(struct net_device *ndev)
                        kfree(ts_skb);
                        if (tag == tfa_tag) {
                                skb_tstamp_tx(skb, &shhwtstamps);
+                               dev_consume_skb_any(skb);
                                break;
+                       } else {
+                               dev_kfree_skb_any(skb);
                        }
                }
                ravb_modify(ndev, TCCR, TCCR_TFR, TCCR_TFR);
@@ -1564,7 +1567,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        }
                        goto unmap;
                }
-               ts_skb->skb = skb;
+               ts_skb->skb = skb_get(skb);
                ts_skb->tag = priv->ts_skb_tag++;
                priv->ts_skb_tag &= 0x3ff;
                list_add_tail(&ts_skb->list, &priv->ts_skb_list);
@@ -1693,6 +1696,7 @@ static int ravb_close(struct net_device *ndev)
        /* Clear the timestamp list */
        list_for_each_entry_safe(ts_skb, ts_skb2, &priv->ts_skb_list, list) {
                list_del(&ts_skb->list);
+               kfree_skb(ts_skb->skb);
                kfree(ts_skb);
        }
 
index 7a5e6c5..276c7ca 100644 (file)
@@ -794,15 +794,16 @@ static int sgiseeq_probe(struct platform_device *pdev)
                printk(KERN_ERR "Sgiseeq: Cannot register net device, "
                       "aborting.\n");
                err = -ENODEV;
-               goto err_out_free_page;
+               goto err_out_free_attrs;
        }
 
        printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr);
 
        return 0;
 
-err_out_free_page:
-       free_page((unsigned long) sp->srings);
+err_out_free_attrs:
+       dma_free_attrs(&pdev->dev, sizeof(*sp->srings), sp->srings,
+                      sp->srings_dma, DMA_ATTR_NON_CONSISTENT);
 err_out_free_dev:
        free_netdev(dev);
 
index 4644b2a..e2e469c 100644 (file)
@@ -1194,10 +1194,8 @@ static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
        int ret;
        struct device *dev = &bsp_priv->pdev->dev;
 
-       if (!ldo) {
-               dev_err(dev, "no regulator found\n");
-               return -1;
-       }
+       if (!ldo)
+               return 0;
 
        if (enable) {
                ret = regulator_enable(ldo);
index 4083019..f97a409 100644 (file)
@@ -873,7 +873,12 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
        int ret;
        u32 reg, val;
 
-       regmap_field_read(gmac->regmap_field, &val);
+       ret = regmap_field_read(gmac->regmap_field, &val);
+       if (ret) {
+               dev_err(priv->device, "Fail to read from regmap field.\n");
+               return ret;
+       }
+
        reg = gmac->variant->default_syscon_value;
        if (reg != val)
                dev_warn(priv->device,
index 37c0bc6..6c305b6 100644 (file)
@@ -94,7 +94,7 @@ static int tc_fill_entry(struct stmmac_priv *priv,
        struct stmmac_tc_entry *entry, *frag = NULL;
        struct tc_u32_sel *sel = cls->knode.sel;
        u32 off, data, mask, real_off, rem;
-       u32 prio = cls->common.prio;
+       u32 prio = cls->common.prio << 16;
        int ret;
 
        /* Only 1 match per entry */
index 32a8974..a46b8b2 100644 (file)
@@ -2775,6 +2775,7 @@ static int cpsw_probe(struct platform_device *pdev)
        if (!cpsw)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, cpsw);
        cpsw->dev = dev;
 
        mode = devm_gpiod_get_array_optional(dev, "mode", GPIOD_OUT_LOW);
@@ -2879,7 +2880,6 @@ static int cpsw_probe(struct platform_device *pdev)
                goto clean_cpts;
        }
 
-       platform_set_drvdata(pdev, cpsw);
        priv = netdev_priv(ndev);
        priv->cpsw = cpsw;
        priv->ndev = ndev;
index 8479a44..12466a7 100644 (file)
@@ -1504,7 +1504,7 @@ tc35815_rx(struct net_device *dev, int limit)
                        pci_unmap_single(lp->pci_dev,
                                         lp->rx_skbs[cur_bd].skb_dma,
                                         RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
+                       if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN != 0)
                                memmove(skb->data, skb->data - NET_IP_ALIGN,
                                        pkt_len);
                        data = skb_put(skb, pkt_len);
index 78a7de3..c62f474 100644 (file)
@@ -371,9 +371,10 @@ tsi108_stat_carry_one(int carry, int carry_bit, int carry_shift,
 static void tsi108_stat_carry(struct net_device *dev)
 {
        struct tsi108_prv_data *data = netdev_priv(dev);
+       unsigned long flags;
        u32 carry1, carry2;
 
-       spin_lock_irq(&data->misclock);
+       spin_lock_irqsave(&data->misclock, flags);
 
        carry1 = TSI_READ(TSI108_STAT_CARRY1);
        carry2 = TSI_READ(TSI108_STAT_CARRY2);
@@ -441,7 +442,7 @@ static void tsi108_stat_carry(struct net_device *dev)
                              TSI108_STAT_TXPAUSEDROP_CARRY,
                              &data->tx_pause_drop);
 
-       spin_unlock_irq(&data->misclock);
+       spin_unlock_irqrestore(&data->misclock, flags);
 }
 
 /* Read a stat counter atomically with respect to carries.
index 331c16d..23281ae 100644 (file)
@@ -344,10 +344,10 @@ static void sp_bump(struct sixpack *sp, char cmd)
 
        sp->dev->stats.rx_bytes += count;
 
-       if ((skb = dev_alloc_skb(count)) == NULL)
+       if ((skb = dev_alloc_skb(count + 1)) == NULL)
                goto out_mem;
 
-       ptr = skb_put(skb, count);
+       ptr = skb_put(skb, count + 1);
        *ptr++ = cmd;   /* KISS command */
 
        memcpy(ptr, sp->cooked_buf + 1, count);
index 3544e19..e8fce6d 100644 (file)
@@ -1239,12 +1239,15 @@ static void netvsc_get_stats64(struct net_device *net,
                               struct rtnl_link_stats64 *t)
 {
        struct net_device_context *ndev_ctx = netdev_priv(net);
-       struct netvsc_device *nvdev = rcu_dereference_rtnl(ndev_ctx->nvdev);
+       struct netvsc_device *nvdev;
        struct netvsc_vf_pcpu_stats vf_tot;
        int i;
 
+       rcu_read_lock();
+
+       nvdev = rcu_dereference(ndev_ctx->nvdev);
        if (!nvdev)
-               return;
+               goto out;
 
        netdev_stats_to_stats64(t, &net->stats);
 
@@ -1283,6 +1286,8 @@ static void netvsc_get_stats64(struct net_device *net,
                t->rx_packets   += packets;
                t->multicast    += multicast;
        }
+out:
+       rcu_read_unlock();
 }
 
 static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
index b41696e..c20e7ef 100644 (file)
@@ -802,7 +802,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
                err = hwsim_subscribe_all_others(phy);
                if (err < 0) {
                        mutex_unlock(&hwsim_phys_lock);
-                       goto err_reg;
+                       goto err_subscribe;
                }
        }
        list_add_tail(&phy->list, &hwsim_phys);
@@ -812,6 +812,8 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
 
        return idx;
 
+err_subscribe:
+       ieee802154_unregister_hw(phy->hw);
 err_reg:
        kfree(pib);
 err_pib:
@@ -901,9 +903,9 @@ static __init int hwsim_init_module(void)
        return 0;
 
 platform_drv:
-       genl_unregister_family(&hwsim_genl_family);
-platform_dev:
        platform_device_unregister(mac802154hwsim_dev);
+platform_dev:
+       genl_unregister_family(&hwsim_genl_family);
        return rc;
 }
 
index c5c417a..bcc40a2 100644 (file)
@@ -73,46 +73,47 @@ static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
        debugfs_remove_recursive(nsim_dev_port->ddir);
 }
 
+static struct net *nsim_devlink_net(struct devlink *devlink)
+{
+       return &init_net;
+}
+
 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV4_FIB, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
 }
 
 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV4_FIB_RULES, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
 }
 
 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV6_FIB, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
 }
 
 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
 {
-       struct nsim_dev *nsim_dev = priv;
+       struct net *net = priv;
 
-       return nsim_fib_get_val(nsim_dev->fib_data,
-                               NSIM_RESOURCE_IPV6_FIB_RULES, false);
+       return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
 }
 
 static int nsim_dev_resources_register(struct devlink *devlink)
 {
-       struct nsim_dev *nsim_dev = devlink_priv(devlink);
        struct devlink_resource_size_params params = {
                .size_max = (u64)-1,
                .size_granularity = 1,
                .unit = DEVLINK_RESOURCE_UNIT_ENTRY
        };
+       struct net *net = nsim_devlink_net(devlink);
        int err;
        u64 n;
 
@@ -126,8 +127,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                goto out;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV4_FIB, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
        err = devlink_resource_register(devlink, "fib", n,
                                        NSIM_RESOURCE_IPV4_FIB,
                                        NSIM_RESOURCE_IPV4, &params);
@@ -136,8 +136,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                return err;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV4_FIB_RULES, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
        err = devlink_resource_register(devlink, "fib-rules", n,
                                        NSIM_RESOURCE_IPV4_FIB_RULES,
                                        NSIM_RESOURCE_IPV4, &params);
@@ -156,8 +155,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                goto out;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV6_FIB, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
        err = devlink_resource_register(devlink, "fib", n,
                                        NSIM_RESOURCE_IPV6_FIB,
                                        NSIM_RESOURCE_IPV6, &params);
@@ -166,8 +164,7 @@ static int nsim_dev_resources_register(struct devlink *devlink)
                return err;
        }
 
-       n = nsim_fib_get_val(nsim_dev->fib_data,
-                            NSIM_RESOURCE_IPV6_FIB_RULES, true);
+       n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
        err = devlink_resource_register(devlink, "fib-rules", n,
                                        NSIM_RESOURCE_IPV6_FIB_RULES,
                                        NSIM_RESOURCE_IPV6, &params);
@@ -179,19 +176,19 @@ static int nsim_dev_resources_register(struct devlink *devlink)
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV4_FIB,
                                          nsim_dev_ipv4_fib_resource_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV4_FIB_RULES,
                                          nsim_dev_ipv4_fib_rules_res_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV6_FIB,
                                          nsim_dev_ipv6_fib_resource_occ_get,
-                                         nsim_dev);
+                                         net);
        devlink_resource_occ_get_register(devlink,
                                          NSIM_RESOURCE_IPV6_FIB_RULES,
                                          nsim_dev_ipv6_fib_rules_res_occ_get,
-                                         nsim_dev);
+                                         net);
 out:
        return err;
 }
@@ -199,11 +196,11 @@ out:
 static int nsim_dev_reload(struct devlink *devlink,
                           struct netlink_ext_ack *extack)
 {
-       struct nsim_dev *nsim_dev = devlink_priv(devlink);
        enum nsim_resource_id res_ids[] = {
                NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
                NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
        };
+       struct net *net = nsim_devlink_net(devlink);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
@@ -212,8 +209,7 @@ static int nsim_dev_reload(struct devlink *devlink,
 
                err = devlink_resource_size_get(devlink, res_ids[i], &val);
                if (!err) {
-                       err = nsim_fib_set_max(nsim_dev->fib_data,
-                                              res_ids[i], val, extack);
+                       err = nsim_fib_set_max(net, res_ids[i], val, extack);
                        if (err)
                                return err;
                }
@@ -285,15 +281,9 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
        mutex_init(&nsim_dev->port_list_lock);
        nsim_dev->fw_update_status = true;
 
-       nsim_dev->fib_data = nsim_fib_create();
-       if (IS_ERR(nsim_dev->fib_data)) {
-               err = PTR_ERR(nsim_dev->fib_data);
-               goto err_devlink_free;
-       }
-
        err = nsim_dev_resources_register(devlink);
        if (err)
-               goto err_fib_destroy;
+               goto err_devlink_free;
 
        err = devlink_register(devlink, &nsim_bus_dev->dev);
        if (err)
@@ -315,8 +305,6 @@ err_dl_unregister:
        devlink_unregister(devlink);
 err_resources_unregister:
        devlink_resources_unregister(devlink, NULL);
-err_fib_destroy:
-       nsim_fib_destroy(nsim_dev->fib_data);
 err_devlink_free:
        devlink_free(devlink);
        return ERR_PTR(err);
@@ -330,7 +318,6 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
        nsim_dev_debugfs_exit(nsim_dev);
        devlink_unregister(devlink);
        devlink_resources_unregister(devlink, NULL);
-       nsim_fib_destroy(nsim_dev->fib_data);
        mutex_destroy(&nsim_dev->port_list_lock);
        devlink_free(devlink);
 }
index 8c57ba7..f61d094 100644 (file)
@@ -18,6 +18,7 @@
 #include <net/ip_fib.h>
 #include <net/ip6_fib.h>
 #include <net/fib_rules.h>
+#include <net/netns/generic.h>
 
 #include "netdevsim.h"
 
@@ -32,14 +33,15 @@ struct nsim_per_fib_data {
 };
 
 struct nsim_fib_data {
-       struct notifier_block fib_nb;
        struct nsim_per_fib_data ipv4;
        struct nsim_per_fib_data ipv6;
 };
 
-u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, bool max)
+static unsigned int nsim_fib_net_id;
+
+u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max)
 {
+       struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
        struct nsim_fib_entry *entry;
 
        switch (res_id) {
@@ -62,10 +64,10 @@ u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
        return max ? entry->max : entry->num;
 }
 
-int nsim_fib_set_max(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, u64 val,
+int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val,
                     struct netlink_ext_ack *extack)
 {
+       struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id);
        struct nsim_fib_entry *entry;
        int err = 0;
 
@@ -118,9 +120,9 @@ static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
        return err;
 }
 
-static int nsim_fib_rule_event(struct nsim_fib_data *data,
-                              struct fib_notifier_info *info, bool add)
+static int nsim_fib_rule_event(struct fib_notifier_info *info, bool add)
 {
+       struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
        struct netlink_ext_ack *extack = info->extack;
        int err = 0;
 
@@ -155,9 +157,9 @@ static int nsim_fib_account(struct nsim_fib_entry *entry, bool add,
        return err;
 }
 
-static int nsim_fib_event(struct nsim_fib_data *data,
-                         struct fib_notifier_info *info, bool add)
+static int nsim_fib_event(struct fib_notifier_info *info, bool add)
 {
+       struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id);
        struct netlink_ext_ack *extack = info->extack;
        int err = 0;
 
@@ -176,22 +178,18 @@ static int nsim_fib_event(struct nsim_fib_data *data,
 static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
                             void *ptr)
 {
-       struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
-                                                 fib_nb);
        struct fib_notifier_info *info = ptr;
        int err = 0;
 
        switch (event) {
        case FIB_EVENT_RULE_ADD: /* fall through */
        case FIB_EVENT_RULE_DEL:
-               err = nsim_fib_rule_event(data, info,
-                                         event == FIB_EVENT_RULE_ADD);
+               err = nsim_fib_rule_event(info, event == FIB_EVENT_RULE_ADD);
                break;
 
        case FIB_EVENT_ENTRY_ADD:  /* fall through */
        case FIB_EVENT_ENTRY_DEL:
-               err = nsim_fib_event(data, info,
-                                    event == FIB_EVENT_ENTRY_ADD);
+               err = nsim_fib_event(info, event == FIB_EVENT_ENTRY_ADD);
                break;
        }
 
@@ -201,23 +199,30 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
 /* inconsistent dump, trying again */
 static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
 {
-       struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
-                                                 fib_nb);
+       struct nsim_fib_data *data;
+       struct net *net;
+
+       rcu_read_lock();
+       for_each_net_rcu(net) {
+               data = net_generic(net, nsim_fib_net_id);
+
+               data->ipv4.fib.num = 0ULL;
+               data->ipv4.rules.num = 0ULL;
 
-       data->ipv4.fib.num = 0ULL;
-       data->ipv4.rules.num = 0ULL;
-       data->ipv6.fib.num = 0ULL;
-       data->ipv6.rules.num = 0ULL;
+               data->ipv6.fib.num = 0ULL;
+               data->ipv6.rules.num = 0ULL;
+       }
+       rcu_read_unlock();
 }
 
-struct nsim_fib_data *nsim_fib_create(void)
-{
-       struct nsim_fib_data *data;
-       int err;
+static struct notifier_block nsim_fib_nb = {
+       .notifier_call = nsim_fib_event_nb,
+};
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
+/* Initialize per network namespace state */
+static int __net_init nsim_fib_netns_init(struct net *net)
+{
+       struct nsim_fib_data *data = net_generic(net, nsim_fib_net_id);
 
        data->ipv4.fib.max = (u64)-1;
        data->ipv4.rules.max = (u64)-1;
@@ -225,22 +230,37 @@ struct nsim_fib_data *nsim_fib_create(void)
        data->ipv6.fib.max = (u64)-1;
        data->ipv6.rules.max = (u64)-1;
 
-       data->fib_nb.notifier_call = nsim_fib_event_nb;
-       err = register_fib_notifier(&data->fib_nb, nsim_fib_dump_inconsistent);
-       if (err) {
-               pr_err("Failed to register fib notifier\n");
-               goto err_out;
-       }
+       return 0;
+}
 
-       return data;
+static struct pernet_operations nsim_fib_net_ops = {
+       .init = nsim_fib_netns_init,
+       .id   = &nsim_fib_net_id,
+       .size = sizeof(struct nsim_fib_data),
+};
 
-err_out:
-       kfree(data);
-       return ERR_PTR(err);
+void nsim_fib_exit(void)
+{
+       unregister_pernet_subsys(&nsim_fib_net_ops);
+       unregister_fib_notifier(&nsim_fib_nb);
 }
 
-void nsim_fib_destroy(struct nsim_fib_data *data)
+int nsim_fib_init(void)
 {
-       unregister_fib_notifier(&data->fib_nb);
-       kfree(data);
+       int err;
+
+       err = register_pernet_subsys(&nsim_fib_net_ops);
+       if (err < 0) {
+               pr_err("Failed to register pernet subsystem\n");
+               goto err_out;
+       }
+
+       err = register_fib_notifier(&nsim_fib_nb, nsim_fib_dump_inconsistent);
+       if (err < 0) {
+               pr_err("Failed to register fib notifier\n");
+               goto err_out;
+       }
+
+err_out:
+       return err;
 }
index 0740940..55f57f7 100644 (file)
@@ -357,12 +357,18 @@ static int __init nsim_module_init(void)
        if (err)
                goto err_dev_exit;
 
-       err = rtnl_link_register(&nsim_link_ops);
+       err = nsim_fib_init();
        if (err)
                goto err_bus_exit;
 
+       err = rtnl_link_register(&nsim_link_ops);
+       if (err)
+               goto err_fib_exit;
+
        return 0;
 
+err_fib_exit:
+       nsim_fib_exit();
 err_bus_exit:
        nsim_bus_exit();
 err_dev_exit:
@@ -373,6 +379,7 @@ err_dev_exit:
 static void __exit nsim_module_exit(void)
 {
        rtnl_link_unregister(&nsim_link_ops);
+       nsim_fib_exit();
        nsim_bus_exit();
        nsim_dev_exit();
 }
index 79c05af..9404637 100644 (file)
@@ -169,12 +169,10 @@ int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
                      unsigned int port_index);
 
-struct nsim_fib_data *nsim_fib_create(void);
-void nsim_fib_destroy(struct nsim_fib_data *fib_data);
-u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, bool max);
-int nsim_fib_set_max(struct nsim_fib_data *fib_data,
-                    enum nsim_resource_id res_id, u64 val,
+int nsim_fib_init(void);
+void nsim_fib_exit(void);
+u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max);
+int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val,
                     struct netlink_ext_ack *extack);
 
 #if IS_ENABLED(CONFIG_XFRM_OFFLOAD)
index 222ccd9..6ad8b1c 100644 (file)
@@ -257,36 +257,20 @@ static int at803x_config_init(struct phy_device *phydev)
         *   after HW reset: RX delay enabled and TX delay disabled
         *   after SW reset: RX delay enabled, while TX delay retains the
         *   value before reset.
-        *
-        * So let's first disable the RX and TX delays in PHY and enable
-        * them based on the mode selected (this also takes care of RGMII
-        * mode where we expect delays to be disabled)
         */
-
-       ret = at803x_disable_rx_delay(phydev);
-       if (ret < 0)
-               return ret;
-       ret = at803x_disable_tx_delay(phydev);
-       if (ret < 0)
-               return ret;
-
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-           phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
-               /* If RGMII_ID or RGMII_RXID are specified enable RX delay,
-                * otherwise keep it disabled
-                */
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
                ret = at803x_enable_rx_delay(phydev);
-               if (ret < 0)
-                       return ret;
-       }
+       else
+               ret = at803x_disable_rx_delay(phydev);
+       if (ret < 0)
+               return ret;
 
        if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
-           phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
-               /* If RGMII_ID or RGMII_TXID are specified enable TX delay,
-                * otherwise keep it disabled
-                */
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
                ret = at803x_enable_tx_delay(phydev);
-       }
+       else
+               ret = at803x_disable_tx_delay(phydev);
 
        return ret;
 }
index b9d4145..7935593 100644 (file)
@@ -219,6 +219,20 @@ int genphy_c45_read_link(struct phy_device *phydev)
        int val, devad;
        bool link = true;
 
+       if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
+               val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+               if (val < 0)
+                       return val;
+
+               /* Autoneg is being started, therefore disregard current
+                * link status and report link as down.
+                */
+               if (val & MDIO_AN_CTRL1_RESTART) {
+                       phydev->link = 0;
+                       return 0;
+               }
+       }
+
        while (mmd_mask && link) {
                devad = __ffs(mmd_mask);
                mmd_mask &= ~BIT(devad);
@@ -509,6 +523,32 @@ int genphy_c45_read_status(struct phy_device *phydev)
 }
 EXPORT_SYMBOL_GPL(genphy_c45_read_status);
 
+/**
+ * genphy_c45_config_aneg - restart auto-negotiation or forced setup
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ *   advertising, and then restart auto-negotiation.  If it is not
+ *   enabled, then we force a configuration.
+ */
+int genphy_c45_config_aneg(struct phy_device *phydev)
+{
+       bool changed = false;
+       int ret;
+
+       if (phydev->autoneg == AUTONEG_DISABLE)
+               return genphy_c45_pma_setup_forced(phydev);
+
+       ret = genphy_c45_an_config_aneg(phydev);
+       if (ret < 0)
+               return ret;
+       if (ret > 0)
+               changed = true;
+
+       return genphy_c45_check_and_restart_aneg(phydev, changed);
+}
+EXPORT_SYMBOL_GPL(genphy_c45_config_aneg);
+
 /* The gen10g_* functions are the old Clause 45 stub */
 
 int gen10g_config_aneg(struct phy_device *phydev)
index ef7aa73..6b0f893 100644 (file)
@@ -507,7 +507,7 @@ static int phy_config_aneg(struct phy_device *phydev)
         * allowed to call genphy_config_aneg()
         */
        if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
-               return -EOPNOTSUPP;
+               return genphy_c45_config_aneg(phydev);
 
        return genphy_config_aneg(phydev);
 }
index 7ddd91d..27ebc2c 100644 (file)
@@ -1752,7 +1752,17 @@ EXPORT_SYMBOL(genphy_aneg_done);
  */
 int genphy_update_link(struct phy_device *phydev)
 {
-       int status;
+       int status = 0, bmcr;
+
+       bmcr = phy_read(phydev, MII_BMCR);
+       if (bmcr < 0)
+               return bmcr;
+
+       /* Autoneg is being started, therefore disregard BMSR value and
+        * report link as down.
+        */
+       if (bmcr & BMCR_ANRESTART)
+               goto done;
 
        /* The link state is latched low so that momentary link
         * drops can be detected. Do not double-read the status
index a45c5de..a5a57ca 100644 (file)
@@ -376,8 +376,8 @@ static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_stat
  *  Local device  Link partner
  *  Pause AsymDir Pause AsymDir Result
  *    1     X       1     X     TX+RX
- *    0     1       1     1     RX
- *    1     1       0     1     TX
+ *    0     1       1     1     TX
+ *    1     1       0     1     RX
  */
 static void phylink_resolve_flow(struct phylink *pl,
                                 struct phylink_link_state *state)
@@ -398,7 +398,7 @@ static void phylink_resolve_flow(struct phylink *pl,
                        new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
                else if (pause & MLO_PAUSE_ASYM)
                        new_pause = state->pause & MLO_PAUSE_SYM ?
-                                MLO_PAUSE_RX : MLO_PAUSE_TX;
+                                MLO_PAUSE_TX : MLO_PAUSE_RX;
        } else {
                new_pause = pl->link_config.pause & MLO_PAUSE_TXRX_MASK;
        }
index abfa0da..e8089de 100644 (file)
@@ -1004,6 +1004,8 @@ static void __team_compute_features(struct team *team)
 
        team->dev->vlan_features = vlan_features;
        team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
+                                    NETIF_F_HW_VLAN_CTAG_TX |
+                                    NETIF_F_HW_VLAN_STAG_TX |
                                     NETIF_F_GSO_UDP_L4;
        team->dev->hard_header_len = max_hard_header_len;
 
index db16d7a..aab0be4 100644 (file)
@@ -787,7 +787,8 @@ static void tun_detach_all(struct net_device *dev)
 }
 
 static int tun_attach(struct tun_struct *tun, struct file *file,
-                     bool skip_filter, bool napi, bool napi_frags)
+                     bool skip_filter, bool napi, bool napi_frags,
+                     bool publish_tun)
 {
        struct tun_file *tfile = file->private_data;
        struct net_device *dev = tun->dev;
@@ -870,7 +871,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
         * initialized tfile; otherwise we risk using half-initialized
         * object.
         */
-       rcu_assign_pointer(tfile->tun, tun);
+       if (publish_tun)
+               rcu_assign_pointer(tfile->tun, tun);
        rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
        tun->numqueues++;
        tun_set_real_num_queues(tun);
@@ -2730,7 +2732,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER,
                                 ifr->ifr_flags & IFF_NAPI,
-                                ifr->ifr_flags & IFF_NAPI_FRAGS);
+                                ifr->ifr_flags & IFF_NAPI_FRAGS, true);
                if (err < 0)
                        return err;
 
@@ -2829,13 +2831,17 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
-                                ifr->ifr_flags & IFF_NAPI_FRAGS);
+                                ifr->ifr_flags & IFF_NAPI_FRAGS, false);
                if (err < 0)
                        goto err_free_flow;
 
                err = register_netdevice(tun->dev);
                if (err < 0)
                        goto err_detach;
+               /* free_netdev() won't check refcnt, to aovid race
+                * with dev_put() we need publish tun after registration.
+                */
+               rcu_assign_pointer(tfile->tun, tun);
        }
 
        netif_carrier_on(tun->dev);
@@ -2978,7 +2984,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
                if (ret < 0)
                        goto unlock;
                ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI,
-                                tun->flags & IFF_NAPI_FRAGS);
+                                tun->flags & IFF_NAPI_FRAGS, true);
        } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
                tun = rtnl_dereference(tfile->tun);
                if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)
index 8458e88..32f53de 100644 (file)
@@ -206,7 +206,15 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                goto bad_desc;
        }
 skip:
-       if (rndis && header.usb_cdc_acm_descriptor &&
+       /* Communcation class functions with bmCapabilities are not
+        * RNDIS.  But some Wireless class RNDIS functions use
+        * bmCapabilities for their own purpose. The failsafe is
+        * therefore applied only to Communication class RNDIS
+        * functions.  The rndis test is redundant, but a cheap
+        * optimization.
+        */
+       if (rndis && is_rndis(&intf->cur_altsetting->desc) &&
+           header.usb_cdc_acm_descriptor &&
            header.usb_cdc_acm_descriptor->bmCapabilities) {
                dev_dbg(&intf->dev,
                        "ACM capabilities %02x, not really RNDIS?\n",
index 5519248..32b08b1 100644 (file)
@@ -163,7 +163,8 @@ static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
        }
        if (!timeout) {
                dev_err(&udev->dev, "firmware not ready in time\n");
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto err;
        }
 
        /* enable ethernet mode (?) */
index d62b670..fc5895f 100644 (file)
@@ -113,16 +113,16 @@ kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr)
        status = kalmia_send_init_packet(dev, usb_buf, ARRAY_SIZE(init_msg_1),
                                         usb_buf, 24);
        if (status != 0)
-               return status;
+               goto out;
 
        memcpy(usb_buf, init_msg_2, 12);
        status = kalmia_send_init_packet(dev, usb_buf, ARRAY_SIZE(init_msg_2),
                                         usb_buf, 28);
        if (status != 0)
-               return status;
+               goto out;
 
        memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN);
-
+out:
        kfree(usb_buf);
        return status;
 }
index 3d92ea6..f033fee 100644 (file)
@@ -3792,7 +3792,7 @@ static int lan78xx_probe(struct usb_interface *intf,
        ret = register_netdev(netdev);
        if (ret != 0) {
                netif_err(dev, probe, netdev, "couldn't register the device\n");
-               goto out3;
+               goto out4;
        }
 
        usb_set_intfdata(intf, dev);
@@ -3807,12 +3807,14 @@ static int lan78xx_probe(struct usb_interface *intf,
 
        ret = lan78xx_phy_init(dev);
        if (ret < 0)
-               goto out4;
+               goto out5;
 
        return 0;
 
-out4:
+out5:
        unregister_netdev(netdev);
+out4:
+       usb_free_urb(dev->urb_intr);
 out3:
        lan78xx_unbind(dev, intf);
 out2:
index 0cc03a9..04137ac 100644 (file)
@@ -799,8 +799,11 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
        ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
                              RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
                              value, index, tmp, size, 500);
+       if (ret < 0)
+               memset(data, 0xff, size);
+       else
+               memcpy(data, tmp, size);
 
-       memcpy(data, tmp, size);
        kfree(tmp);
 
        return ret;
@@ -4018,8 +4021,7 @@ static int rtl8152_close(struct net_device *netdev)
 #ifdef CONFIG_PM_SLEEP
        unregister_pm_notifier(&tp->pm_notifier);
 #endif
-       if (!test_bit(RTL8152_UNPLUG, &tp->flags))
-               napi_disable(&tp->napi);
+       napi_disable(&tp->napi);
        clear_bit(WORK_ENABLE, &tp->flags);
        usb_kill_urb(tp->intr_urb);
        cancel_delayed_work_sync(&tp->schedule);
@@ -5350,7 +5352,6 @@ static int rtl8152_probe(struct usb_interface *intf,
        return 0;
 
 out1:
-       netif_napi_del(&tp->napi);
        usb_set_intfdata(intf, NULL);
 out:
        free_netdev(netdev);
@@ -5365,7 +5366,6 @@ static void rtl8152_disconnect(struct usb_interface *intf)
        if (tp) {
                rtl_set_unplug(tp);
 
-               netif_napi_del(&tp->napi);
                unregister_netdev(tp->netdev);
                cancel_delayed_work_sync(&tp->hw_phy_work);
                tp->rtl_ops.unload(tp);
index 4f3de0a..ba98e09 100644 (file)
@@ -1331,7 +1331,7 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
                }
        }
 
-       if (rq->vq->num_free > virtqueue_get_vring_size(rq->vq) / 2) {
+       if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) {
                if (!try_fill_recv(vi, rq, GFP_ATOMIC))
                        schedule_delayed_work(&vi->refill, 0);
        }
index d743496..0e6a515 100644 (file)
@@ -1115,7 +1115,7 @@ static void lmc_running_reset (struct net_device *dev) /*fold00*/
     sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
     LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
 
-    lmc_trace(dev, "lmc_runnin_reset_out");
+    lmc_trace(dev, "lmc_running_reset_out");
 }
 
 
index e9fc168..489cba9 100644 (file)
@@ -351,13 +351,15 @@ int i2400m_barker_db_init(const char *_options)
                        }
                        result = i2400m_barker_db_add(barker);
                        if (result < 0)
-                               goto error_add;
+                               goto error_parse_add;
                }
                kfree(options_orig);
        }
        return 0;
 
+error_parse_add:
 error_parse:
+       kfree(options_orig);
 error_add:
        kfree(i2400m_barker_db);
        return result;
index 6642bcb..8efb493 100644 (file)
@@ -127,6 +127,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev,
                        "%d\n", result);
        result = 0;
 error_cmd:
+       kfree(cmd);
        kfree_skb(ack_skb);
 error_msg_to_dev:
 error_alloc:
index 1f500cd..55b7132 100644 (file)
@@ -556,6 +556,30 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = {
        .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
 };
 
+const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = {
+       .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)",
+       .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = {
+       .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)",
+       .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+       IWL_DEVICE_22500,
+       /*
+        * This device doesn't support receiving BlockAck with a large bitmap
+        * so we need to restrict the size of transmitted aggregation to the
+        * HT size; mac80211 would otherwise pick the HE max (256) by default.
+        */
+       .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
 const struct iwl_cfg iwl22000_2ax_cfg_jf = {
        .name = "Intel(R) Dual Band Wireless AX 22000",
        .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
index 1c1bf1b..6c04f82 100644 (file)
@@ -577,6 +577,8 @@ extern const struct iwl_cfg iwl_ax1650i_cfg_quz_hr;
 extern const struct iwl_cfg iwl_ax1650s_cfg_quz_hr;
 extern const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0;
 extern const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0;
+extern const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0;
+extern const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0;
 extern const struct iwl_cfg killer1650x_2ax_cfg;
 extern const struct iwl_cfg killer1650w_2ax_cfg;
 extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0;
index cb22d44..fe776e3 100644 (file)
@@ -554,7 +554,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                cpu_to_le32(vif->bss_conf.use_short_slot ?
                            MAC_FLG_SHORT_SLOT : 0);
 
-       cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
+       cmd->filter_flags = 0;
 
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
@@ -623,6 +623,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
        /* We need the dtim_period to set the MAC as associated */
        if (vif->bss_conf.assoc && vif->bss_conf.dtim_period &&
            !force_assoc_off) {
+               struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+               u8 ap_sta_id = mvmvif->ap_sta_id;
                u32 dtim_offs;
 
                /*
@@ -658,6 +660,29 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
                               dtim_offs);
 
                ctxt_sta->is_assoc = cpu_to_le32(1);
+
+               /*
+                * allow multicast data frames only as long as the station is
+                * authorized, i.e., GTK keys are already installed (if needed)
+                */
+               if (ap_sta_id < IWL_MVM_STATION_COUNT) {
+                       struct ieee80211_sta *sta;
+
+                       rcu_read_lock();
+
+                       sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]);
+                       if (!IS_ERR_OR_NULL(sta)) {
+                               struct iwl_mvm_sta *mvmsta =
+                                       iwl_mvm_sta_from_mac80211(sta);
+
+                               if (mvmsta->sta_state ==
+                                   IEEE80211_STA_AUTHORIZED)
+                                       cmd.filter_flags |=
+                                               cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
+                       }
+
+                       rcu_read_unlock();
+               }
        } else {
                ctxt_sta->is_assoc = cpu_to_le32(0);
 
@@ -703,7 +728,8 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
                                       MAC_FILTER_IN_CONTROL_AND_MGMT |
                                       MAC_FILTER_IN_BEACON |
                                       MAC_FILTER_IN_PROBE_REQUEST |
-                                      MAC_FILTER_IN_CRC32);
+                                      MAC_FILTER_IN_CRC32 |
+                                      MAC_FILTER_ACCEPT_GRP);
        ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
 
        /* Allocate sniffer station */
@@ -727,7 +753,8 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
-                                      MAC_FILTER_IN_PROBE_REQUEST);
+                                      MAC_FILTER_IN_PROBE_REQUEST |
+                                      MAC_FILTER_ACCEPT_GRP);
 
        /* cmd.ibss.beacon_time/cmd.ibss.beacon_tsf are curently ignored */
        cmd.ibss.bi = cpu_to_le32(vif->bss_conf.beacon_int);
index 1c904b5..a7bc00d 100644 (file)
@@ -3327,10 +3327,20 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                /* enable beacon filtering */
                WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
 
+               /*
+                * Now that the station is authorized, i.e., keys were already
+                * installed, need to indicate to the FW that
+                * multicast data frames can be forwarded to the driver
+                */
+               iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+
                iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
                                     true);
        } else if (old_state == IEEE80211_STA_AUTHORIZED &&
                   new_state == IEEE80211_STA_ASSOC) {
+               /* Multicast data frames are no longer allowed */
+               iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+
                /* disable beacon filtering */
                ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
                WARN_ON(ret &&
index de711c1..3b12e7a 100644 (file)
@@ -1062,7 +1062,28 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        iwl_trans->cfg = &iwl9560_2ac_cfg_qu_c0_jf_b0;
                else if (iwl_trans->cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
                        iwl_trans->cfg = &iwl9560_2ac_160_cfg_qu_c0_jf_b0;
+               else if (iwl_trans->cfg == &killer1650s_2ax_cfg_qu_b0_hr_b0)
+                       iwl_trans->cfg = &killer1650s_2ax_cfg_qu_c0_hr_b0;
+               else if (iwl_trans->cfg == &killer1650i_2ax_cfg_qu_b0_hr_b0)
+                       iwl_trans->cfg = &killer1650i_2ax_cfg_qu_c0_hr_b0;
        }
+
+       /* same thing for QuZ... */
+       if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QUZ) {
+               if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax101_cfg_quz_hr;
+               else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr)
+                       iwl_trans->cfg = &iwl_ax201_cfg_quz_hr;
+               else if (iwl_trans->cfg == &iwl9461_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9461_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9462_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9462_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9560_2ac_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_cfg_quz_a0_jf_b0_soc;
+               else if (iwl_trans->cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
+                       iwl_trans->cfg = &iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc;
+       }
+
 #endif
 
        pci_set_drvdata(pdev, iwl_trans);
index f5df5b3..db62c83 100644 (file)
@@ -3602,11 +3602,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                }
        } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
                   CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) &&
-                  ((trans->cfg != &iwl_ax200_cfg_cc &&
-                    trans->cfg != &killer1650x_2ax_cfg &&
-                    trans->cfg != &killer1650w_2ax_cfg &&
-                    trans->cfg != &iwl_ax201_cfg_quz_hr) ||
-                   trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0)) {
+                  trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) {
                u32 hw_status;
 
                hw_status = iwl_read_prph(trans, UMAG_GEN_HW_STATUS);
index 38d1103..9ef6b8f 100644 (file)
@@ -99,10 +99,7 @@ void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
        u16 len = byte_cnt;
        __le16 bc_ent;
 
-       if (trans_pcie->bc_table_dword)
-               len = DIV_ROUND_UP(len, 4);
-
-       if (WARN_ON(len > 0xFFF || idx >= txq->n_window))
+       if (WARN(idx >= txq->n_window, "%d >= %d\n", idx, txq->n_window))
                return;
 
        filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) +
@@ -117,11 +114,20 @@ void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
         */
        num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1;
 
-       bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12));
-       if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
+       if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
+               /* Starting from 22560, the HW expects bytes */
+               WARN_ON(trans_pcie->bc_table_dword);
+               WARN_ON(len > 0x3FFF);
+               bc_ent = cpu_to_le16(len | (num_fetch_chunks << 14));
                scd_bc_tbl_gen3->tfd_offset[idx] = bc_ent;
-       else
+       } else {
+               /* Until 22560, the HW expects DW */
+               WARN_ON(!trans_pcie->bc_table_dword);
+               len = DIV_ROUND_UP(len, 4);
+               WARN_ON(len > 0xFFF);
+               bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12));
                scd_bc_tbl->tfd_offset[idx] = bc_ent;
+       }
 }
 
 /*
index 653d347..580387f 100644 (file)
@@ -241,6 +241,9 @@ static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
                }
 
                vs_ie = (struct ieee_types_header *)vendor_ie;
+               if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
+                       IEEE_MAX_IE_SIZE)
+                       return -EINVAL;
                memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
                       vs_ie, vs_ie->len + 2);
                le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2);
index 18f7d9b..0939a8c 100644 (file)
@@ -265,6 +265,8 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
 
        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
        if (rate_ie) {
+               if (rate_ie->len > MWIFIEX_SUPPORTED_RATES)
+                       return;
                memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
                rate_len = rate_ie->len;
        }
@@ -272,8 +274,11 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
                                           params->beacon.tail,
                                           params->beacon.tail_len);
-       if (rate_ie)
+       if (rate_ie) {
+               if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len)
+                       return;
                memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
+       }
 
        return;
 }
@@ -391,6 +396,8 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv,
                                            params->beacon.tail_len);
        if (vendor_ie) {
                wmm_ie = vendor_ie;
+               if (*(wmm_ie + 1) > sizeof(struct mwifiex_types_wmm_info))
+                       return;
                memcpy(&bss_cfg->wmm_info, wmm_ie +
                       sizeof(struct ieee_types_header), *(wmm_ie + 1));
                priv->wmm_enabled = 1;
index 40c0d53..9d4426f 100644 (file)
@@ -59,6 +59,11 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
                dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
        }
 
+       if (is_mt7630(dev)) {
+               dev->mt76.cap.has_5ghz = false;
+               dev_dbg(dev->mt76.dev, "mask out 5GHz support\n");
+       }
+
        if (!mt76x02_field_valid(nic_conf1 & 0xff))
                nic_conf1 &= 0xff00;
 
index 4585e1b..6117e6c 100644 (file)
@@ -62,6 +62,19 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
        mt76x0e_stop_hw(dev);
 }
 
+static int
+mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+               struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+               struct ieee80211_key_conf *key)
+{
+       struct mt76x02_dev *dev = hw->priv;
+
+       if (is_mt7630(dev))
+               return -EOPNOTSUPP;
+
+       return mt76x02_set_key(hw, cmd, vif, sta, key);
+}
+
 static void
 mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
              u32 queues, bool drop)
@@ -78,7 +91,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
        .configure_filter = mt76x02_configure_filter,
        .bss_info_changed = mt76x02_bss_info_changed,
        .sta_state = mt76_sta_state,
-       .set_key = mt76x02_set_key,
+       .set_key = mt76x0e_set_key,
        .conf_tx = mt76x02_conf_tx,
        .sw_scan_start = mt76x02_sw_scan,
        .sw_scan_complete = mt76x02_sw_scan_complete,
index 627ed1f..645f4d1 100644 (file)
@@ -136,11 +136,11 @@ static const struct ieee80211_ops mt76x0u_ops = {
        .release_buffered_frames = mt76_release_buffered_frames,
 };
 
-static int mt76x0u_init_hardware(struct mt76x02_dev *dev)
+static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset)
 {
        int err;
 
-       mt76x0_chip_onoff(dev, true, true);
+       mt76x0_chip_onoff(dev, true, reset);
 
        if (!mt76x02_wait_for_mac(&dev->mt76))
                return -ETIMEDOUT;
@@ -173,7 +173,7 @@ static int mt76x0u_register_device(struct mt76x02_dev *dev)
        if (err < 0)
                goto out_err;
 
-       err = mt76x0u_init_hardware(dev);
+       err = mt76x0u_init_hardware(dev, true);
        if (err < 0)
                goto out_err;
 
@@ -309,7 +309,7 @@ static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf)
        if (ret < 0)
                goto err;
 
-       ret = mt76x0u_init_hardware(dev);
+       ret = mt76x0u_init_hardware(dev, false);
        if (ret)
                goto err;
 
index c9b957a..f1cdcd6 100644 (file)
@@ -1654,13 +1654,18 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
 
        offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
 
-       rt2800_register_multiread(rt2x00dev, offset,
-                                 &iveiv_entry, sizeof(iveiv_entry));
-       if ((crypto->cipher == CIPHER_TKIP) ||
-           (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
-           (crypto->cipher == CIPHER_AES))
-               iveiv_entry.iv[3] |= 0x20;
-       iveiv_entry.iv[3] |= key->keyidx << 6;
+       if (crypto->cmd == SET_KEY) {
+               rt2800_register_multiread(rt2x00dev, offset,
+                                         &iveiv_entry, sizeof(iveiv_entry));
+               if ((crypto->cipher == CIPHER_TKIP) ||
+                   (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
+                   (crypto->cipher == CIPHER_AES))
+                       iveiv_entry.iv[3] |= 0x20;
+               iveiv_entry.iv[3] |= key->keyidx << 6;
+       } else {
+               memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+       }
+
        rt2800_register_multiwrite(rt2x00dev, offset,
                                   &iveiv_entry, sizeof(iveiv_entry));
 }
@@ -4237,24 +4242,18 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        switch (rt2x00dev->default_ant.rx_chain_num) {
        case 3:
                /* Turn on tertiary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN, 1);
                /* fall-through */
        case 2:
                /* Turn on secondary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
                /* fall-through */
        case 1:
                /* Turn on primary LNAs */
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN,
-                                  rf->channel > 14);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN,
-                                  rf->channel <= 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
                break;
        }
 
@@ -6094,6 +6093,15 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                rt2800_delete_wcid_attr(rt2x00dev, i);
        }
 
+       /*
+        * Clear encryption initialization vectors on start, but keep them
+        * for watchdog reset. Otherwise we will have wrong IVs and not be
+        * able to keep connections after reset.
+        */
+       if (!test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags))
+               for (i = 0; i < 256; i++)
+                       rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
+
        /*
         * Clear all beacons
         */
index 7e43690..2b216ed 100644 (file)
@@ -658,6 +658,7 @@ enum rt2x00_state_flags {
        DEVICE_STATE_ENABLED_RADIO,
        DEVICE_STATE_SCANNING,
        DEVICE_STATE_FLUSHING,
+       DEVICE_STATE_RESET,
 
        /*
         * Driver configuration
index 35414f9..9d15823 100644 (file)
@@ -1256,13 +1256,14 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
 
 int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
 {
-       int retval;
+       int retval = 0;
 
        if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
                /*
                 * This is special case for ieee80211_restart_hw(), otherwise
                 * mac80211 never call start() two times in row without stop();
                 */
+               set_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
                rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
                rt2x00lib_stop(rt2x00dev);
        }
@@ -1273,14 +1274,14 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
         */
        retval = rt2x00lib_load_firmware(rt2x00dev);
        if (retval)
-               return retval;
+               goto out;
 
        /*
         * Initialize the device.
         */
        retval = rt2x00lib_initialize(rt2x00dev);
        if (retval)
-               return retval;
+               goto out;
 
        rt2x00dev->intf_ap_count = 0;
        rt2x00dev->intf_sta_count = 0;
@@ -1289,11 +1290,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
        /* Enable the radio */
        retval = rt2x00lib_enable_radio(rt2x00dev);
        if (retval)
-               return retval;
+               goto out;
 
        set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
 
-       return 0;
+out:
+       clear_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
+       return retval;
 }
 
 void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
index f5048d4..760eaff 100644 (file)
@@ -645,7 +645,6 @@ fail_rx:
        kfree(rsi_dev->tx_buffer);
 
 fail_eps:
-       kfree(rsi_dev);
 
        return status;
 }
index 1d9940d..c9262ff 100644 (file)
@@ -925,6 +925,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
                        nskb = xenvif_alloc_skb(0);
                        if (unlikely(nskb == NULL)) {
+                               skb_shinfo(skb)->nr_frags = 0;
                                kfree_skb(skb);
                                xenvif_tx_err(queue, &txreq, extra_count, idx);
                                if (net_ratelimit())
@@ -940,6 +941,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. */
+                               skb_shinfo(skb)->nr_frags = 0;
                                kfree_skb(skb);
                                kfree_skb(nskb);
                                break;
index e428500..7eda62a 100644 (file)
@@ -316,7 +316,7 @@ static int st95hf_echo_command(struct st95hf_context *st95context)
                                          &echo_response);
        if (result) {
                dev_err(&st95context->spicontext.spidev->dev,
-                       "err: echo response receieve error = 0x%x\n", result);
+                       "err: echo response receive error = 0x%x\n", result);
                return result;
        }
 
index 3e7b11c..cb98b8f 100644 (file)
@@ -655,6 +655,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        resource_size_t start, size;
        struct nd_region *nd_region;
        unsigned long npfns, align;
+       u32 end_trunc;
        struct nd_pfn_sb *pfn_sb;
        phys_addr_t offset;
        const char *sig;
@@ -696,6 +697,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        size = resource_size(&nsio->res);
        npfns = PHYS_PFN(size - SZ_8K);
        align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT));
+       end_trunc = start + size - ALIGN_DOWN(start + size, align);
        if (nd_pfn->mode == PFN_MODE_PMEM) {
                /*
                 * The altmap should be padded out to the block size used
@@ -714,7 +716,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
                return -ENXIO;
        }
 
-       npfns = PHYS_PFN(size - offset);
+       npfns = PHYS_PFN(size - offset - end_trunc);
        pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
        pfn_sb->dataoff = cpu_to_le64(offset);
        pfn_sb->npfns = cpu_to_le64(npfns);
@@ -723,6 +725,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
        pfn_sb->version_major = cpu_to_le16(1);
        pfn_sb->version_minor = cpu_to_le16(3);
+       pfn_sb->end_trunc = cpu_to_le32(end_trunc);
        pfn_sb->align = cpu_to_le32(nd_pfn->align);
        checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
        pfn_sb->checksum = cpu_to_le64(checksum);
index 8f3fbe5..d3d6b7b 100644 (file)
@@ -1286,6 +1286,9 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
         */
        if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
                mutex_lock(&ctrl->scan_lock);
+               mutex_lock(&ctrl->subsys->lock);
+               nvme_mpath_start_freeze(ctrl->subsys);
+               nvme_mpath_wait_freeze(ctrl->subsys);
                nvme_start_freeze(ctrl);
                nvme_wait_freeze(ctrl);
        }
@@ -1316,6 +1319,8 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
                nvme_update_formats(ctrl);
        if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
                nvme_unfreeze(ctrl);
+               nvme_mpath_unfreeze(ctrl->subsys);
+               mutex_unlock(&ctrl->subsys->lock);
                mutex_unlock(&ctrl->scan_lock);
        }
        if (effects & NVME_CMD_EFFECTS_CCC)
@@ -1715,6 +1720,7 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
        if (ns->head->disk) {
                nvme_update_disk_info(ns->head->disk, ns, id);
                blk_queue_stack_limits(ns->head->disk->queue, ns->queue);
+               revalidate_disk(ns->head->disk);
        }
 #endif
 }
@@ -2251,6 +2257,16 @@ static const struct nvme_core_quirk_entry core_quirks[] = {
                .vid = 0x1179,
                .mn = "THNSF5256GPUK TOSHIBA",
                .quirks = NVME_QUIRK_NO_APST,
+       },
+       {
+               /*
+                * This LiteON CL1-3D*-Q11 firmware version has a race
+                * condition associated with actions related to suspend to idle
+                * LiteON has resolved the problem in future firmware
+                */
+               .vid = 0x14a4,
+               .fr = "22301111",
+               .quirks = NVME_QUIRK_SIMPLE_SUSPEND,
        }
 };
 
@@ -2487,6 +2503,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
                if (ret) {
                        dev_err(ctrl->device,
                                "failed to register subsystem device.\n");
+                       put_device(&subsys->dev);
                        goto out_unlock;
                }
                ida_init(&subsys->ns_ida);
@@ -2509,7 +2526,6 @@ out_put_subsystem:
        nvme_put_subsystem(subsys);
 out_unlock:
        mutex_unlock(&nvme_subsystems_lock);
-       put_device(&subsys->dev);
        return ret;
 }
 
@@ -2591,6 +2607,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                        goto out_free;
        }
 
+       if (!(ctrl->ops->flags & NVME_F_FABRICS))
+               ctrl->cntlid = le16_to_cpu(id->cntlid);
+
        if (!ctrl->identified) {
                int i;
 
@@ -2691,7 +2710,6 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                        goto out_free;
                }
        } else {
-               ctrl->cntlid = le16_to_cpu(id->cntlid);
                ctrl->hmpre = le32_to_cpu(id->hmpre);
                ctrl->hmmin = le32_to_cpu(id->hmmin);
                ctrl->hmminds = le32_to_cpu(id->hmminds);
@@ -3571,6 +3589,13 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
        struct nvme_ns *ns, *next;
        LIST_HEAD(ns_list);
 
+       /*
+        * make sure to requeue I/O to all namespaces as these
+        * might result from the scan itself and must complete
+        * for the scan_work to make progress
+        */
+       nvme_mpath_clear_ctrl_paths(ctrl);
+
        /* prevent racing with ns scanning */
        flush_work(&ctrl->scan_work);
 
index 4f0d0d1..af831d3 100644 (file)
@@ -12,6 +12,36 @@ module_param(multipath, bool, 0444);
 MODULE_PARM_DESC(multipath,
        "turn on native support for multiple controllers per subsystem");
 
+void nvme_mpath_unfreeze(struct nvme_subsystem *subsys)
+{
+       struct nvme_ns_head *h;
+
+       lockdep_assert_held(&subsys->lock);
+       list_for_each_entry(h, &subsys->nsheads, entry)
+               if (h->disk)
+                       blk_mq_unfreeze_queue(h->disk->queue);
+}
+
+void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys)
+{
+       struct nvme_ns_head *h;
+
+       lockdep_assert_held(&subsys->lock);
+       list_for_each_entry(h, &subsys->nsheads, entry)
+               if (h->disk)
+                       blk_mq_freeze_queue_wait(h->disk->queue);
+}
+
+void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
+{
+       struct nvme_ns_head *h;
+
+       lockdep_assert_held(&subsys->lock);
+       list_for_each_entry(h, &subsys->nsheads, entry)
+               if (h->disk)
+                       blk_freeze_queue_start(h->disk->queue);
+}
+
 /*
  * If multipathing is enabled we need to always use the subsystem instance
  * number for numbering our devices to avoid conflicts between subsystems that
@@ -104,18 +134,34 @@ static const char *nvme_ana_state_names[] = {
        [NVME_ANA_CHANGE]               = "change",
 };
 
-void nvme_mpath_clear_current_path(struct nvme_ns *ns)
+bool nvme_mpath_clear_current_path(struct nvme_ns *ns)
 {
        struct nvme_ns_head *head = ns->head;
+       bool changed = false;
        int node;
 
        if (!head)
-               return;
+               goto out;
 
        for_each_node(node) {
-               if (ns == rcu_access_pointer(head->current_path[node]))
+               if (ns == rcu_access_pointer(head->current_path[node])) {
                        rcu_assign_pointer(head->current_path[node], NULL);
+                       changed = true;
+               }
        }
+out:
+       return changed;
+}
+
+void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
+{
+       struct nvme_ns *ns;
+
+       mutex_lock(&ctrl->scan_lock);
+       list_for_each_entry(ns, &ctrl->namespaces, list)
+               if (nvme_mpath_clear_current_path(ns))
+                       kblockd_schedule_work(&ns->head->requeue_work);
+       mutex_unlock(&ctrl->scan_lock);
 }
 
 static bool nvme_path_is_disabled(struct nvme_ns *ns)
@@ -226,6 +272,24 @@ inline struct nvme_ns *nvme_find_path(struct nvme_ns_head *head)
        return ns;
 }
 
+static bool nvme_available_path(struct nvme_ns_head *head)
+{
+       struct nvme_ns *ns;
+
+       list_for_each_entry_rcu(ns, &head->list, siblings) {
+               switch (ns->ctrl->state) {
+               case NVME_CTRL_LIVE:
+               case NVME_CTRL_RESETTING:
+               case NVME_CTRL_CONNECTING:
+                       /* fallthru */
+                       return true;
+               default:
+                       break;
+               }
+       }
+       return false;
+}
+
 static blk_qc_t nvme_ns_head_make_request(struct request_queue *q,
                struct bio *bio)
 {
@@ -252,14 +316,14 @@ static blk_qc_t nvme_ns_head_make_request(struct request_queue *q,
                                      disk_devt(ns->head->disk),
                                      bio->bi_iter.bi_sector);
                ret = direct_make_request(bio);
-       } else if (!list_empty_careful(&head->list)) {
-               dev_warn_ratelimited(dev, "no path available - requeuing I/O\n");
+       } else if (nvme_available_path(head)) {
+               dev_warn_ratelimited(dev, "no usable path - requeuing I/O\n");
 
                spin_lock_irq(&head->requeue_lock);
                bio_list_add(&head->requeue_list, bio);
                spin_unlock_irq(&head->requeue_lock);
        } else {
-               dev_warn_ratelimited(dev, "no path - failing I/O\n");
+               dev_warn_ratelimited(dev, "no available path - failing I/O\n");
 
                bio->bi_status = BLK_STS_IOERR;
                bio_endio(bio);
@@ -364,6 +428,7 @@ static void nvme_mpath_set_live(struct nvme_ns *ns)
                srcu_read_unlock(&head->srcu, srcu_idx);
        }
 
+       synchronize_srcu(&ns->head->srcu);
        kblockd_schedule_work(&ns->head->requeue_work);
 }
 
index 26b563f..2d678fb 100644 (file)
@@ -92,6 +92,11 @@ enum nvme_quirks {
         * Broken Write Zeroes.
         */
        NVME_QUIRK_DISABLE_WRITE_ZEROES         = (1 << 9),
+
+       /*
+        * Force simple suspend/resume path.
+        */
+       NVME_QUIRK_SIMPLE_SUSPEND               = (1 << 10),
 };
 
 /*
@@ -490,6 +495,9 @@ static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
        return ctrl->ana_log_buf != NULL;
 }
 
+void nvme_mpath_unfreeze(struct nvme_subsystem *subsys);
+void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys);
+void nvme_mpath_start_freeze(struct nvme_subsystem *subsys);
 void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
                        struct nvme_ctrl *ctrl, int *flags);
 void nvme_failover_req(struct request *req);
@@ -500,7 +508,8 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head);
 int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
 void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
 void nvme_mpath_stop(struct nvme_ctrl *ctrl);
-void nvme_mpath_clear_current_path(struct nvme_ns *ns);
+bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
+void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
 struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
 
 static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
@@ -548,7 +557,11 @@ static inline void nvme_mpath_add_disk(struct nvme_ns *ns,
 static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head)
 {
 }
-static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
+static inline bool nvme_mpath_clear_current_path(struct nvme_ns *ns)
+{
+       return false;
+}
+static inline void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
 {
 }
 static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
@@ -568,6 +581,15 @@ static inline void nvme_mpath_uninit(struct nvme_ctrl *ctrl)
 static inline void nvme_mpath_stop(struct nvme_ctrl *ctrl)
 {
 }
+static inline void nvme_mpath_unfreeze(struct nvme_subsystem *subsys)
+{
+}
+static inline void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys)
+{
+}
+static inline void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
+{
+}
 #endif /* CONFIG_NVME_MULTIPATH */
 
 #ifdef CONFIG_NVM
index db160ce..732d5b6 100644 (file)
@@ -2695,7 +2695,7 @@ static void nvme_async_probe(void *data, async_cookie_t cookie)
 {
        struct nvme_dev *dev = data;
 
-       nvme_reset_ctrl_sync(&dev->ctrl);
+       flush_work(&dev->ctrl.reset_work);
        flush_work(&dev->ctrl.scan_work);
        nvme_put_ctrl(&dev->ctrl);
 }
@@ -2761,6 +2761,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
 
+       nvme_reset_ctrl(&dev->ctrl);
        nvme_get_ctrl(&dev->ctrl);
        async_schedule(nvme_async_probe, dev);
 
@@ -2846,7 +2847,7 @@ static int nvme_resume(struct device *dev)
        struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev));
        struct nvme_ctrl *ctrl = &ndev->ctrl;
 
-       if (pm_resume_via_firmware() || !ctrl->npss ||
+       if (ndev->last_ps == U32_MAX ||
            nvme_set_power_state(ctrl, ndev->last_ps) != 0)
                nvme_reset_ctrl(ctrl);
        return 0;
@@ -2859,6 +2860,8 @@ static int nvme_suspend(struct device *dev)
        struct nvme_ctrl *ctrl = &ndev->ctrl;
        int ret = -EBUSY;
 
+       ndev->last_ps = U32_MAX;
+
        /*
         * The platform does not remove power for a kernel managed suspend so
         * use host managed nvme power settings for lowest idle power if
@@ -2866,8 +2869,15 @@ static int nvme_suspend(struct device *dev)
         * shutdown.  But if the firmware is involved after the suspend or the
         * device does not support any non-default power states, shut down the
         * device fully.
+        *
+        * If ASPM is not enabled for the device, shut down the device and allow
+        * the PCI bus layer to put it into D3 in order to take the PCIe link
+        * down, so as to allow the platform to achieve its minimum low-power
+        * state (which may not be possible if the link is up).
         */
-       if (pm_suspend_via_firmware() || !ctrl->npss) {
+       if (pm_suspend_via_firmware() || !ctrl->npss ||
+           !pcie_aspm_enabled(pdev) ||
+           (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) {
                nvme_dev_disable(ndev, true);
                return 0;
        }
@@ -2880,7 +2890,6 @@ static int nvme_suspend(struct device *dev)
            ctrl->state != NVME_CTRL_ADMIN_ONLY)
                goto unfreeze;
 
-       ndev->last_ps = 0;
        ret = nvme_get_power_state(ctrl, &ndev->last_ps);
        if (ret < 0)
                goto unfreeze;
index a249db5..1a6449b 100644 (file)
@@ -562,13 +562,17 @@ out_destroy_cm_id:
        return ret;
 }
 
+static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
+{
+       rdma_disconnect(queue->cm_id);
+       ib_drain_qp(queue->qp);
+}
+
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
        if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
                return;
-
-       rdma_disconnect(queue->cm_id);
-       ib_drain_qp(queue->qp);
+       __nvme_rdma_stop_queue(queue);
 }
 
 static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
@@ -607,11 +611,13 @@ static int nvme_rdma_start_queue(struct nvme_rdma_ctrl *ctrl, int idx)
        else
                ret = nvmf_connect_admin_queue(&ctrl->ctrl);
 
-       if (!ret)
+       if (!ret) {
                set_bit(NVME_RDMA_Q_LIVE, &queue->flags);
-       else
+       } else {
+               __nvme_rdma_stop_queue(queue);
                dev_info(ctrl->ctrl.device,
                        "failed to connect queue: %d ret=%d\n", idx, ret);
+       }
        return ret;
 }
 
index cd52b9f..98613a4 100644 (file)
@@ -675,6 +675,7 @@ static void nvmet_port_subsys_drop_link(struct config_item *parent,
 
 found:
        list_del(&p->entry);
+       nvmet_port_del_ctrls(port, subsys);
        nvmet_port_disc_changed(port, subsys);
 
        if (list_empty(&port->subsystems))
index dad0243..3a67e24 100644 (file)
@@ -46,6 +46,9 @@ inline u16 errno_to_nvme_status(struct nvmet_req *req, int errno)
        u16 status;
 
        switch (errno) {
+       case 0:
+               status = NVME_SC_SUCCESS;
+               break;
        case -ENOSPC:
                req->error_loc = offsetof(struct nvme_rw_command, length);
                status = NVME_SC_CAP_EXCEEDED | NVME_SC_DNR;
@@ -280,6 +283,18 @@ void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops)
 }
 EXPORT_SYMBOL_GPL(nvmet_unregister_transport);
 
+void nvmet_port_del_ctrls(struct nvmet_port *port, struct nvmet_subsys *subsys)
+{
+       struct nvmet_ctrl *ctrl;
+
+       mutex_lock(&subsys->lock);
+       list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
+               if (ctrl->port == port)
+                       ctrl->ops->delete_ctrl(ctrl);
+       }
+       mutex_unlock(&subsys->lock);
+}
+
 int nvmet_enable_port(struct nvmet_port *port)
 {
        const struct nvmet_fabrics_ops *ops;
index b16dc39..0940c50 100644 (file)
@@ -654,6 +654,14 @@ static void nvme_loop_remove_port(struct nvmet_port *port)
        mutex_lock(&nvme_loop_ports_mutex);
        list_del_init(&port->entry);
        mutex_unlock(&nvme_loop_ports_mutex);
+
+       /*
+        * Ensure any ctrls that are in the process of being
+        * deleted are in fact deleted before we return
+        * and free the port. This is to prevent active
+        * ctrls from using a port after it's freed.
+        */
+       flush_workqueue(nvme_delete_wq);
 }
 
 static const struct nvmet_fabrics_ops nvme_loop_ops = {
index 6ee66c6..c51f8dd 100644 (file)
@@ -418,6 +418,9 @@ void nvmet_port_send_ana_event(struct nvmet_port *port);
 int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
 void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);
 
+void nvmet_port_del_ctrls(struct nvmet_port *port,
+                         struct nvmet_subsys *subsys);
+
 int nvmet_enable_port(struct nvmet_port *port);
 void nvmet_disable_port(struct nvmet_port *port);
 
index 9cdf14b..223d617 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/debugfs.h>
 #include <linux/serial_core.h>
 #include <linux/sysfs.h>
+#include <linux/random.h>
 
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #include <asm/page.h>
@@ -1044,6 +1045,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 {
        int l;
        const char *p;
+       const void *rng_seed;
 
        pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
 
@@ -1078,6 +1080,18 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 
        pr_debug("Command line is: %s\n", (char*)data);
 
+       rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
+       if (rng_seed && l > 0) {
+               add_bootloader_randomness(rng_seed, l);
+
+               /* try to clear seed so it won't be found. */
+               fdt_nop_property(initial_boot_params, node, "rng-seed");
+
+               /* update CRC check value */
+               of_fdt_crc32 = crc32_be(~0, initial_boot_params,
+                               fdt_totalsize(initial_boot_params));
+       }
+
        /* break now */
        return 1;
 }
index 7f84bb4..a296eaf 100644 (file)
@@ -277,7 +277,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
  * of_irq_parse_one - Resolve an interrupt for a device
  * @device: the device whose interrupt is to be resolved
  * @index: index of the interrupt to resolve
- * @out_irq: structure of_irq filled by this function
+ * @out_irq: structure of_phandle_args filled by this function
  *
  * This function resolves an interrupt for a node by walking the interrupt tree,
  * finding which interrupt controller node it is attached to, and returning the
index c1b67dd..83c7662 100644 (file)
@@ -206,16 +206,22 @@ static int adjust_local_phandle_references(struct device_node *local_fixups,
        for_each_child_of_node(local_fixups, child) {
 
                for_each_child_of_node(overlay, overlay_child)
-                       if (!node_name_cmp(child, overlay_child))
+                       if (!node_name_cmp(child, overlay_child)) {
+                               of_node_put(overlay_child);
                                break;
+                       }
 
-               if (!overlay_child)
+               if (!overlay_child) {
+                       of_node_put(child);
                        return -EINVAL;
+               }
 
                err = adjust_local_phandle_references(child, overlay_child,
                                phandle_delta);
-               if (err)
+               if (err) {
+                       of_node_put(child);
                        return err;
+               }
        }
 
        return 0;
index 3c73010..2f1cac8 100644 (file)
@@ -6,7 +6,7 @@
 **     (c) Copyright 1999 SuSE GmbH
 **     (c) Copyright 1999,2000 Hewlett-Packard Company
 **     (c) Copyright 2000 Grant Grundler
-**     (c) Copyright 2006 Helge Deller
+**     (c) Copyright 2006-2019 Helge Deller
 **
 **
 **     This module provides access to Dino PCI bus (config/IOport spaces)
@@ -156,6 +156,15 @@ static inline struct dino_device *DINO_DEV(struct pci_hba_data *hba)
        return container_of(hba, struct dino_device, hba);
 }
 
+/* Check if PCI device is behind a Card-mode Dino. */
+static int pci_dev_is_behind_card_dino(struct pci_dev *dev)
+{
+       struct dino_device *dino_dev;
+
+       dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge));
+       return is_card_dino(&dino_dev->hba.dev->id);
+}
+
 /*
  * Dino Configuration Space Accessor Functions
  */
@@ -437,6 +446,21 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
 
+#ifdef CONFIG_TULIP
+static void pci_fixup_tulip(struct pci_dev *dev)
+{
+       if (!pci_dev_is_behind_card_dino(dev))
+               return;
+       if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM))
+               return;
+       pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n",
+               pci_name(dev));
+       /* Disable this card by zeroing the PCI resources */
+       memset(&dev->resource[0], 0, sizeof(dev->resource[0]));
+       memset(&dev->resource[1], 0, sizeof(dev->resource[1]));
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip);
+#endif /* CONFIG_TULIP */
 
 static void __init
 dino_bios_init(void)
@@ -863,14 +887,14 @@ static int __init dino_common_init(struct parisc_device *dev,
 #define CUJO_RAVEN_BADPAGE     0x01003000UL
 #define CUJO_FIREHAWK_BADPAGE  0x01607000UL
 
-static const char *dino_vers[] = {
+static const char dino_vers[][4] = {
        "2.0",
        "2.1",
        "3.0",
        "3.1"
 };
 
-static const char *cujo_vers[] = {
+static const char cujo_vers[][4] = {
        "1.0",
        "2.0"
 };
index 9c08222..f54a6f4 100644 (file)
@@ -93,7 +93,7 @@ static int configure_memory(const unsigned char *buf,
                        res->start = mem_parent->start + get_24(buf+len+2);
                        res->end = res->start + get_16(buf+len+5)*1024;
                        res->flags = IORESOURCE_MEM;
-                       printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
+                       pr_cont("memory %pR ", res);
                        result = request_resource(mem_parent, res);
                        if (result < 0) {
                                printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
@@ -123,7 +123,7 @@ static int configure_irq(const unsigned char *buf)
        for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
                c = get_8(buf+len);
                
-               printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
+               pr_cont("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
                if (c & HPEE_IRQ_TRIG_LEVEL) {
                        eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
                } else {
@@ -153,7 +153,7 @@ static int configure_dma(const unsigned char *buf)
        
        for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
                c = get_8(buf+len);
-               printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
+               pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
                /* fixme: maybe initialize the dma channel withthe timing ? */
                len+=2;      
                if (!(c & HPEE_DMA_MORE)) {
@@ -183,7 +183,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
                        res->start = get_16(buf+len+1);
                        res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
                        res->flags = IORESOURCE_IO;
-                       printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
+                       pr_cont("ioports %pR ", res);
                        result = request_resource(io_parent, res);
                        if (result < 0) {
                                printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
@@ -401,7 +401,7 @@ static int parse_slot_config(int slot,
                }
                pos = p0 + function_len;
        }
-       printk("\n");
+       pr_cont("\n");
        if (!id_string_used) {
                kfree(board);
        }
index 44e12c8..e60e686 100644 (file)
@@ -61,8 +61,6 @@ static int __init hppb_probe(struct parisc_device *dev)
                }
                card = card->next;
        }
-       printk(KERN_INFO "Found GeckoBoa at 0x%llx\n",
-                       (unsigned long long) dev->hpa.start);
 
        card->hpa = dev->hpa.start;
        card->mmio_region.name = "HP-PB Bus";
@@ -72,10 +70,11 @@ static int __init hppb_probe(struct parisc_device *dev)
        card->mmio_region.end = gsc_readl(dev->hpa.start + IO_IO_HIGH) - 1;
 
        status = ccio_request_resource(dev, &card->mmio_region);
-       if(status < 0) {
-               printk(KERN_ERR "%s: failed to claim HP-PB bus space (%pR)\n",
-                       __FILE__, &card->mmio_region);
-       }
+
+       pr_info("Found GeckoBoa at %pap, bus space %pR,%s claimed.\n",
+                       &dev->hpa.start,
+                       &card->mmio_region,
+                       (status < 0) ? " not":"" );
 
         return 0;
 }
index e9f78eb..e7b493c 100644 (file)
@@ -147,15 +147,6 @@ config HOTPLUG_PCI_RPA_DLPAR
 
          When in doubt, say N.
 
-config HOTPLUG_PCI_SGI
-       tristate "SGI PCI Hotplug Support"
-       depends on IA64_SGI_SN2 || IA64_GENERIC
-       help
-         Say Y here if you want to use the SGI Altix Hotplug
-         Driver for PCI devices.
-
-         When in doubt, say N.
-
 config HOTPLUG_PCI_S390
        bool "System z PCI Hotplug Support"
        depends on S390 && 64BIT
index 7e33316..5196983 100644 (file)
@@ -18,7 +18,6 @@ obj-$(CONFIG_HOTPLUG_PCI_SHPC)                += shpchp.o
 obj-$(CONFIG_HOTPLUG_PCI_POWERNV)      += pnv-php.o
 obj-$(CONFIG_HOTPLUG_PCI_RPA)          += rpaphp.o
 obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)    += rpadlpar_io.o
-obj-$(CONFIG_HOTPLUG_PCI_SGI)          += sgi_hotplug.o
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)         += acpiphp.o
 obj-$(CONFIG_HOTPLUG_PCI_S390)         += s390_pci_hpc.o
 
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
deleted file mode 100644 (file)
index 231f5bd..0000000
+++ /dev/null
@@ -1,700 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved.
- *
- * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
- * Work to add BIOS PROM support was completed by Mike Habeck.
- */
-
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_hotplug.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/l1.h>
-#include <asm/sn/module.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/sn_feature_sets.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/types.h>
-#include <asm/sn/acpi.h>
-
-#include "../pci.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
-MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-
-
-/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
-#define PCI_SLOT_ALREADY_UP            2       /* slot already up */
-#define PCI_SLOT_ALREADY_DOWN          3       /* slot already down */
-#define PCI_L1_ERR                     7       /* L1 console command error */
-#define PCI_EMPTY_33MHZ                        15      /* empty 33 MHz bus */
-
-
-#define PCIIO_ASIC_TYPE_TIOCA          4
-#define PCI_L1_QSIZE                   128     /* our L1 message buffer size */
-#define SN_MAX_HP_SLOTS                        32      /* max hotplug slots */
-#define SN_SLOT_NAME_SIZE              33      /* size of name string */
-
-/* internal list head */
-static struct list_head sn_hp_list;
-
-/* hotplug_slot struct's private pointer */
-struct slot {
-       int device_num;
-       struct pci_bus *pci_bus;
-       /* this struct for glue internal only */
-       struct hotplug_slot hotplug_slot;
-       struct list_head hp_list;
-       char physical_path[SN_SLOT_NAME_SIZE];
-};
-
-struct pcibr_slot_enable_resp {
-       int resp_sub_errno;
-       char resp_l1_msg[PCI_L1_QSIZE + 1];
-};
-
-struct pcibr_slot_disable_resp {
-       int resp_sub_errno;
-       char resp_l1_msg[PCI_L1_QSIZE + 1];
-};
-
-enum sn_pci_req_e {
-       PCI_REQ_SLOT_ELIGIBLE,
-       PCI_REQ_SLOT_DISABLE
-};
-
-static int enable_slot(struct hotplug_slot *slot);
-static int disable_slot(struct hotplug_slot *slot);
-static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
-
-static const struct hotplug_slot_ops sn_hotplug_slot_ops = {
-       .enable_slot            = enable_slot,
-       .disable_slot           = disable_slot,
-       .get_power_status       = get_power_status,
-};
-
-static DEFINE_MUTEX(sn_hotplug_mutex);
-
-static struct slot *to_slot(struct hotplug_slot *bss_hotplug_slot)
-{
-       return container_of(bss_hotplug_slot, struct slot, hotplug_slot);
-}
-
-static ssize_t path_show(struct pci_slot *pci_slot, char *buf)
-{
-       int retval = -ENOENT;
-       struct slot *slot = to_slot(pci_slot->hotplug);
-
-       if (!slot)
-               return retval;
-
-       retval = sprintf(buf, "%s\n", slot->physical_path);
-       return retval;
-}
-
-static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
-
-static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
-{
-       struct pcibus_info *pcibus_info;
-       u16 busnum, segment, ioboard_type;
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
-
-       /* Check to see if this is a valid slot on 'pci_bus' */
-       if (!(pcibus_info->pbi_valid_devices & (1 << device)))
-               return -EPERM;
-
-       ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
-       busnum = pcibus_info->pbi_buscommon.bs_persist_busnum;
-       segment = pci_domain_nr(pci_bus) & 0xf;
-
-       /* Do not allow hotplug operations on base I/O cards */
-       if ((ioboard_type == L1_BRICKTYPE_IX ||
-            ioboard_type == L1_BRICKTYPE_IA) &&
-           (segment == 1 && busnum == 0 && device != 1))
-               return -EPERM;
-
-       return 1;
-}
-
-static int sn_pci_bus_valid(struct pci_bus *pci_bus)
-{
-       struct pcibus_info *pcibus_info;
-       u32 asic_type;
-       u16 ioboard_type;
-
-       /* Don't register slots hanging off the TIOCA bus */
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
-       asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
-       if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
-               return -EPERM;
-
-       /* Only register slots in I/O Bricks that support hotplug */
-       ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
-       switch (ioboard_type) {
-               case L1_BRICKTYPE_IX:
-               case L1_BRICKTYPE_PX:
-               case L1_BRICKTYPE_IA:
-               case L1_BRICKTYPE_PA:
-               case L1_BOARDTYPE_PCIX3SLOT:
-                       return 1;
-                       break;
-               default:
-                       return -EPERM;
-                       break;
-       }
-
-       return -EIO;
-}
-
-static int sn_hp_slot_private_alloc(struct hotplug_slot **bss_hotplug_slot,
-                                   struct pci_bus *pci_bus, int device,
-                                   char *name)
-{
-       struct pcibus_info *pcibus_info;
-       struct slot *slot;
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
-
-       slot = kzalloc(sizeof(*slot), GFP_KERNEL);
-       if (!slot)
-               return -ENOMEM;
-
-       slot->device_num = device;
-       slot->pci_bus = pci_bus;
-       sprintf(name, "%04x:%02x:%02x",
-               pci_domain_nr(pci_bus),
-               ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
-               device + 1);
-
-       sn_generate_path(pci_bus, slot->physical_path);
-
-       list_add(&slot->hp_list, &sn_hp_list);
-       *bss_hotplug_slot = &slot->hotplug_slot;
-
-       return 0;
-}
-
-static struct hotplug_slot *sn_hp_destroy(void)
-{
-       struct slot *slot;
-       struct pci_slot *pci_slot;
-       struct hotplug_slot *bss_hotplug_slot = NULL;
-
-       list_for_each_entry(slot, &sn_hp_list, hp_list) {
-               bss_hotplug_slot = &slot->hotplug_slot;
-               pci_slot = bss_hotplug_slot->pci_slot;
-               list_del(&slot->hp_list);
-               sysfs_remove_file(&pci_slot->kobj,
-                                 &sn_slot_path_attr.attr);
-               break;
-       }
-       return bss_hotplug_slot;
-}
-
-static void sn_bus_free_data(struct pci_dev *dev)
-{
-       struct pci_bus *subordinate_bus;
-       struct pci_dev *child;
-
-       /* Recursively clean up sn_irq_info structs */
-       if (dev->subordinate) {
-               subordinate_bus = dev->subordinate;
-               list_for_each_entry(child, &subordinate_bus->devices, bus_list)
-                       sn_bus_free_data(child);
-       }
-       /*
-        * Some drivers may use dma accesses during the
-        * driver remove function. We release the sysdata
-        * areas after the driver remove functions have
-        * been called.
-        */
-       sn_bus_store_sysdata(dev);
-       sn_pci_unfixup_slot(dev);
-}
-
-static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
-                         int device_num, char **ssdt)
-{
-       struct slot *slot = to_slot(bss_hotplug_slot);
-       struct pcibus_info *pcibus_info;
-       struct pcibr_slot_enable_resp resp;
-       int rc;
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-
-       /*
-        * Power-on and initialize the slot in the SN
-        * PCI infrastructure.
-        */
-       rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
-
-
-       if (rc == PCI_SLOT_ALREADY_UP) {
-               pci_dbg(slot->pci_bus->self, "is already active\n");
-               return 1; /* return 1 to user */
-       }
-
-       if (rc == PCI_L1_ERR) {
-               pci_dbg(slot->pci_bus->self, "L1 failure %d with message: %s",
-                       resp.resp_sub_errno, resp.resp_l1_msg);
-               return -EPERM;
-       }
-
-       if (rc) {
-               pci_dbg(slot->pci_bus->self, "insert failed with error %d sub-error %d\n",
-                       rc, resp.resp_sub_errno);
-               return -EIO;
-       }
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-       pcibus_info->pbi_enabled_devices |= (1 << device_num);
-
-       return 0;
-}
-
-static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
-                          int device_num, int action)
-{
-       struct slot *slot = to_slot(bss_hotplug_slot);
-       struct pcibus_info *pcibus_info;
-       struct pcibr_slot_disable_resp resp;
-       int rc;
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-
-       rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);
-
-       if ((action == PCI_REQ_SLOT_ELIGIBLE) &&
-           (rc == PCI_SLOT_ALREADY_DOWN)) {
-               pci_dbg(slot->pci_bus->self, "Slot %s already inactive\n", slot->physical_path);
-               return 1; /* return 1 to user */
-       }
-
-       if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) {
-               pci_dbg(slot->pci_bus->self, "Cannot remove last 33MHz card\n");
-               return -EPERM;
-       }
-
-       if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) {
-               pci_dbg(slot->pci_bus->self, "L1 failure %d with message \n%s\n",
-                       resp.resp_sub_errno, resp.resp_l1_msg);
-               return -EPERM;
-       }
-
-       if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) {
-               pci_dbg(slot->pci_bus->self, "remove failed with error %d sub-error %d\n",
-                       rc, resp.resp_sub_errno);
-               return -EIO;
-       }
-
-       if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc)
-               return 0;
-
-       if ((action == PCI_REQ_SLOT_DISABLE) && !rc) {
-               pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-               pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
-               pci_dbg(slot->pci_bus->self, "remove successful\n");
-               return 0;
-       }
-
-       if ((action == PCI_REQ_SLOT_DISABLE) && rc) {
-               pci_dbg(slot->pci_bus->self, "remove failed rc = %d\n", rc);
-       }
-
-       return rc;
-}
-
-/*
- * Power up and configure the slot via a SAL call to PROM.
- * Scan slot (and any children), do any platform specific fixup,
- * and find device driver.
- */
-static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
-{
-       struct slot *slot = to_slot(bss_hotplug_slot);
-       struct pci_bus *new_bus = NULL;
-       struct pci_dev *dev;
-       int num_funcs;
-       int new_ppb = 0;
-       int rc;
-       char *ssdt = NULL;
-       void pcibios_fixup_device_resources(struct pci_dev *);
-
-       /* Serialize the Linux PCI infrastructure */
-       mutex_lock(&sn_hotplug_mutex);
-
-       /*
-        * Power-on and initialize the slot in the SN
-        * PCI infrastructure. Also, retrieve the ACPI SSDT
-        * table for the slot (if ACPI capable PROM).
-        */
-       rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
-       if (rc) {
-               mutex_unlock(&sn_hotplug_mutex);
-               return rc;
-       }
-
-       if (ssdt)
-               ssdt = __va(ssdt);
-       /* Add the new SSDT for the slot to the ACPI namespace */
-       if (SN_ACPI_BASE_SUPPORT() && ssdt) {
-               acpi_status ret;
-
-               ret = acpi_load_table((struct acpi_table_header *)ssdt);
-               if (ACPI_FAILURE(ret)) {
-                       printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
-                              __func__, ret);
-                       /* try to continue on */
-               }
-       }
-
-       num_funcs = pci_scan_slot(slot->pci_bus,
-                                 PCI_DEVFN(slot->device_num + 1, 0));
-       if (!num_funcs) {
-               pci_dbg(slot->pci_bus->self, "no device in slot\n");
-               mutex_unlock(&sn_hotplug_mutex);
-               return -ENODEV;
-       }
-
-       /*
-        * Map SN resources for all functions on the card
-        * to the Linux PCI interface and tell the drivers
-        * about them.
-        */
-       list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
-               if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
-                       continue;
-
-               /* Need to do slot fixup on PPB before fixup of children
-                * (PPB's pcidev_info needs to be in pcidev_info list
-                * before child's SN_PCIDEV_INFO() call to setup
-                * pdi_host_pcidev_info).
-                */
-               pcibios_fixup_device_resources(dev);
-               if (SN_ACPI_BASE_SUPPORT())
-                       sn_acpi_slot_fixup(dev);
-               else
-                       sn_io_slot_fixup(dev);
-               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-                       pci_hp_add_bridge(dev);
-                       if (dev->subordinate) {
-                               new_bus = dev->subordinate;
-                               new_ppb = 1;
-                       }
-               }
-       }
-
-       /*
-        * Add the slot's devices to the ACPI infrastructure */
-       if (SN_ACPI_BASE_SUPPORT() && ssdt) {
-               unsigned long long adr;
-               struct acpi_device *pdevice;
-               acpi_handle phandle;
-               acpi_handle chandle = NULL;
-               acpi_handle rethandle;
-               acpi_status ret;
-
-               phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
-
-               if (acpi_bus_get_device(phandle, &pdevice)) {
-                       pci_dbg(slot->pci_bus->self, "no parent device, assuming NULL\n");
-                       pdevice = NULL;
-               }
-
-               acpi_scan_lock_acquire();
-               /*
-                * Walk the rootbus node's immediate children looking for
-                * the slot's device node(s). There can be more than
-                * one for multifunction devices.
-                */
-               for (;;) {
-                       rethandle = NULL;
-                       ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
-                                                  phandle, chandle,
-                                                  &rethandle);
-
-                       if (ret == AE_NOT_FOUND || rethandle == NULL)
-                               break;
-
-                       chandle = rethandle;
-
-                       ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
-                                                   NULL, &adr);
-
-                       if (ACPI_SUCCESS(ret) &&
-                           (adr>>16) == (slot->device_num + 1)) {
-
-                               ret = acpi_bus_scan(chandle);
-                               if (ACPI_FAILURE(ret)) {
-                                       printk(KERN_ERR "%s: acpi_bus_scan failed (0x%x) for slot %d func %d\n",
-                                              __func__, ret, (int)(adr>>16),
-                                              (int)(adr&0xffff));
-                                       /* try to continue on */
-                               }
-                       }
-               }
-               acpi_scan_lock_release();
-       }
-
-       pci_lock_rescan_remove();
-
-       /* Call the driver for the new device */
-       pci_bus_add_devices(slot->pci_bus);
-       /* Call the drivers for the new devices subordinate to PPB */
-       if (new_ppb)
-               pci_bus_add_devices(new_bus);
-
-       pci_unlock_rescan_remove();
-       mutex_unlock(&sn_hotplug_mutex);
-
-       if (rc == 0)
-               pci_dbg(slot->pci_bus->self, "insert operation successful\n");
-       else
-               pci_dbg(slot->pci_bus->self, "insert operation failed rc = %d\n", rc);
-
-       return rc;
-}
-
-static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
-{
-       struct slot *slot = to_slot(bss_hotplug_slot);
-       struct pci_dev *dev, *temp;
-       int rc;
-       acpi_handle ssdt_hdl = NULL;
-
-       /* Acquire update access to the bus */
-       mutex_lock(&sn_hotplug_mutex);
-
-       /* is it okay to bring this slot down? */
-       rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
-                            PCI_REQ_SLOT_ELIGIBLE);
-       if (rc)
-               goto leaving;
-
-       /* free the ACPI resources for the slot */
-       if (SN_ACPI_BASE_SUPPORT() &&
-               PCI_CONTROLLER(slot->pci_bus)->companion) {
-               unsigned long long adr;
-               struct acpi_device *device;
-               acpi_handle phandle;
-               acpi_handle chandle = NULL;
-               acpi_handle rethandle;
-               acpi_status ret;
-
-               /* Get the rootbus node pointer */
-               phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
-
-               acpi_scan_lock_acquire();
-               /*
-                * Walk the rootbus node's immediate children looking for
-                * the slot's device node(s). There can be more than
-                * one for multifunction devices.
-                */
-               for (;;) {
-                       rethandle = NULL;
-                       ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
-                                                  phandle, chandle,
-                                                  &rethandle);
-
-                       if (ret == AE_NOT_FOUND || rethandle == NULL)
-                               break;
-
-                       chandle = rethandle;
-
-                       ret = acpi_evaluate_integer(chandle,
-                                                   METHOD_NAME__ADR,
-                                                   NULL, &adr);
-                       if (ACPI_SUCCESS(ret) &&
-                           (adr>>16) == (slot->device_num + 1)) {
-                               /* retain the owner id */
-                               ssdt_hdl = chandle;
-
-                               ret = acpi_bus_get_device(chandle,
-                                                         &device);
-                               if (ACPI_SUCCESS(ret))
-                                       acpi_bus_trim(device);
-                       }
-               }
-               acpi_scan_lock_release();
-       }
-
-       pci_lock_rescan_remove();
-       /* Free the SN resources assigned to the Linux device.*/
-       list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
-               if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
-                       continue;
-
-               pci_dev_get(dev);
-               sn_bus_free_data(dev);
-               pci_stop_and_remove_bus_device(dev);
-               pci_dev_put(dev);
-       }
-       pci_unlock_rescan_remove();
-
-       /* Remove the SSDT for the slot from the ACPI namespace */
-       if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) {
-               acpi_status ret;
-               ret = acpi_unload_parent_table(ssdt_hdl);
-               if (ACPI_FAILURE(ret)) {
-                       acpi_handle_err(ssdt_hdl,
-                                       "%s: acpi_unload_parent_table failed (0x%x)\n",
-                                       __func__, ret);
-                       /* try to continue on */
-               }
-       }
-
-       /* free the collected sysdata pointers */
-       sn_bus_free_sysdata();
-
-       /* Deactivate slot */
-       rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
-                            PCI_REQ_SLOT_DISABLE);
- leaving:
-       /* Release the bus lock */
-       mutex_unlock(&sn_hotplug_mutex);
-
-       return rc;
-}
-
-static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
-                                  u8 *value)
-{
-       struct slot *slot = to_slot(bss_hotplug_slot);
-       struct pcibus_info *pcibus_info;
-       u32 power;
-
-       pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-       mutex_lock(&sn_hotplug_mutex);
-       power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
-       *value = power ? 1 : 0;
-       mutex_unlock(&sn_hotplug_mutex);
-       return 0;
-}
-
-static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
-{
-       kfree(to_slot(bss_hotplug_slot));
-}
-
-static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
-{
-       int device;
-       struct pci_slot *pci_slot;
-       struct hotplug_slot *bss_hotplug_slot;
-       char name[SN_SLOT_NAME_SIZE];
-       int rc = 0;
-
-       /*
-        * Currently only four devices are supported,
-        * in the future there maybe more -- up to 32.
-        */
-
-       for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
-               if (sn_pci_slot_valid(pci_bus, device) != 1)
-                       continue;
-
-               if (sn_hp_slot_private_alloc(&bss_hotplug_slot,
-                                            pci_bus, device, name)) {
-                       rc = -ENOMEM;
-                       goto alloc_err;
-               }
-               bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
-
-               rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name);
-               if (rc)
-                       goto register_err;
-
-               pci_slot = bss_hotplug_slot->pci_slot;
-               rc = sysfs_create_file(&pci_slot->kobj,
-                                      &sn_slot_path_attr.attr);
-               if (rc)
-                       goto alloc_err;
-       }
-       pci_dbg(pci_bus->self, "Registered bus with hotplug\n");
-       return rc;
-
-register_err:
-       pci_dbg(pci_bus->self, "bus failed to register with err = %d\n",
-               rc);
-
-       /* destroy THIS element */
-       sn_hp_destroy();
-       sn_release_slot(bss_hotplug_slot);
-
-alloc_err:
-       /* destroy anything else on the list */
-       while ((bss_hotplug_slot = sn_hp_destroy())) {
-               pci_hp_deregister(bss_hotplug_slot);
-               sn_release_slot(bss_hotplug_slot);
-       }
-
-       return rc;
-}
-
-static int __init sn_pci_hotplug_init(void)
-{
-       struct pci_bus *pci_bus = NULL;
-       int rc;
-       int registered = 0;
-
-       if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) {
-               printk(KERN_ERR "%s: PROM version does not support hotplug.\n",
-                      __func__);
-               return -EPERM;
-       }
-
-       INIT_LIST_HEAD(&sn_hp_list);
-
-       while ((pci_bus = pci_find_next_bus(pci_bus))) {
-               if (!pci_bus->sysdata)
-                       continue;
-
-               rc = sn_pci_bus_valid(pci_bus);
-               if (rc != 1) {
-                       pci_dbg(pci_bus->self, "not a valid hotplug bus\n");
-                       continue;
-               }
-               pci_dbg(pci_bus->self, "valid hotplug bus\n");
-
-               rc = sn_hotplug_slot_register(pci_bus);
-               if (!rc) {
-                       registered = 1;
-               } else {
-                       registered = 0;
-                       break;
-               }
-       }
-
-       return registered == 1 ? 0 : -ENODEV;
-}
-
-static void __exit sn_pci_hotplug_exit(void)
-{
-       struct hotplug_slot *bss_hotplug_slot;
-
-       while ((bss_hotplug_slot = sn_hp_destroy())) {
-               pci_hp_deregister(bss_hotplug_slot);
-               sn_release_slot(bss_hotplug_slot);
-       }
-
-       if (!list_empty(&sn_hp_list))
-               printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
-}
-
-module_init(sn_pci_hotplug_init);
-module_exit(sn_pci_hotplug_exit);
index e44af7f..464f8f9 100644 (file)
@@ -1170,6 +1170,26 @@ static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp)
 module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
        NULL, 0644);
 
+/**
+ * pcie_aspm_enabled - Check if PCIe ASPM has been enabled for a device.
+ * @pdev: Target device.
+ */
+bool pcie_aspm_enabled(struct pci_dev *pdev)
+{
+       struct pci_dev *bridge = pci_upstream_bridge(pdev);
+       bool ret;
+
+       if (!bridge)
+               return false;
+
+       mutex_lock(&aspm_lock);
+       ret = bridge->link_state ? !!bridge->link_state->aspm_enabled : false;
+       mutex_unlock(&aspm_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pcie_aspm_enabled);
+
 #ifdef CONFIG_PCIEASPM_DEBUG
 static ssize_t link_state_show(struct device *dev,
                struct device_attribute *attr,
index 208aacf..44c4ae1 100644 (file)
@@ -5256,7 +5256,7 @@ static void quirk_reset_lenovo_thinkpad_p50_nvgpu(struct pci_dev *pdev)
         */
        if (ioread32(map + 0x2240c) & 0x2) {
                pci_info(pdev, FW_BUG "GPU left initialized by EFI, resetting\n");
-               ret = pci_reset_function(pdev);
+               ret = pci_reset_bus(pdev);
                if (ret < 0)
                        pci_err(pdev, "Failed to reset GPU: %d\n", ret);
        }
index da71c74..abcf54f 100644 (file)
@@ -113,8 +113,6 @@ struct smmu_pmu {
        u64 counter_mask;
        u32 options;
        bool global_filter;
-       u32 global_filter_span;
-       u32 global_filter_sid;
 };
 
 #define to_smmu_pmu(p) (container_of(p, struct smmu_pmu, pmu))
@@ -260,6 +258,19 @@ static void smmu_pmu_set_event_filter(struct perf_event *event,
        smmu_pmu_set_smr(smmu_pmu, idx, sid);
 }
 
+static bool smmu_pmu_check_global_filter(struct perf_event *curr,
+                                        struct perf_event *new)
+{
+       if (get_filter_enable(new) != get_filter_enable(curr))
+               return false;
+
+       if (!get_filter_enable(new))
+               return true;
+
+       return get_filter_span(new) == get_filter_span(curr) &&
+              get_filter_stream_id(new) == get_filter_stream_id(curr);
+}
+
 static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
                                       struct perf_event *event, int idx)
 {
@@ -279,17 +290,14 @@ static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
        }
 
        /* Requested settings same as current global settings*/
-       if (span == smmu_pmu->global_filter_span &&
-           sid == smmu_pmu->global_filter_sid)
+       idx = find_first_bit(smmu_pmu->used_counters, num_ctrs);
+       if (idx == num_ctrs ||
+           smmu_pmu_check_global_filter(smmu_pmu->events[idx], event)) {
+               smmu_pmu_set_event_filter(event, 0, span, sid);
                return 0;
+       }
 
-       if (!bitmap_empty(smmu_pmu->used_counters, num_ctrs))
-               return -EAGAIN;
-
-       smmu_pmu_set_event_filter(event, 0, span, sid);
-       smmu_pmu->global_filter_span = span;
-       smmu_pmu->global_filter_sid = sid;
-       return 0;
+       return -EAGAIN;
 }
 
 static int smmu_pmu_get_event_idx(struct smmu_pmu *smmu_pmu,
@@ -312,6 +320,19 @@ static int smmu_pmu_get_event_idx(struct smmu_pmu *smmu_pmu,
        return idx;
 }
 
+static bool smmu_pmu_events_compatible(struct perf_event *curr,
+                                      struct perf_event *new)
+{
+       if (new->pmu != curr->pmu)
+               return false;
+
+       if (to_smmu_pmu(new->pmu)->global_filter &&
+           !smmu_pmu_check_global_filter(curr, new))
+               return false;
+
+       return true;
+}
+
 /*
  * Implementation of abstract pmu functionality required by
  * the core perf events code.
@@ -323,6 +344,7 @@ static int smmu_pmu_event_init(struct perf_event *event)
        struct smmu_pmu *smmu_pmu = to_smmu_pmu(event->pmu);
        struct device *dev = smmu_pmu->dev;
        struct perf_event *sibling;
+       int group_num_events = 1;
        u16 event_id;
 
        if (event->attr.type != event->pmu->type)
@@ -347,18 +369,23 @@ static int smmu_pmu_event_init(struct perf_event *event)
        }
 
        /* Don't allow groups with mixed PMUs, except for s/w events */
-       if (event->group_leader->pmu != event->pmu &&
-           !is_software_event(event->group_leader)) {
-               dev_dbg(dev, "Can't create mixed PMU group\n");
-               return -EINVAL;
+       if (!is_software_event(event->group_leader)) {
+               if (!smmu_pmu_events_compatible(event->group_leader, event))
+                       return -EINVAL;
+
+               if (++group_num_events > smmu_pmu->num_counters)
+                       return -EINVAL;
        }
 
        for_each_sibling_event(sibling, event->group_leader) {
-               if (sibling->pmu != event->pmu &&
-                   !is_software_event(sibling)) {
-                       dev_dbg(dev, "Can't create mixed PMU group\n");
+               if (is_software_event(sibling))
+                       continue;
+
+               if (!smmu_pmu_events_compatible(sibling, event))
+                       return -EINVAL;
+
+               if (++group_num_events > smmu_pmu->num_counters)
                        return -EINVAL;
-               }
        }
 
        hwc->idx = -1;
index 63fe216..ce73457 100644 (file)
@@ -35,6 +35,8 @@
 #define EVENT_CYCLES_COUNTER   0
 #define NUM_COUNTERS           4
 
+#define AXI_MASKING_REVERT     0xffff0000      /* AXI_MASKING(MSB 16bits) + AXI_ID(LSB 16bits) */
+
 #define to_ddr_pmu(p)          container_of(p, struct ddr_pmu, pmu)
 
 #define DDR_PERF_DEV_NAME      "imx8_ddr"
 
 static DEFINE_IDA(ddr_ida);
 
+/* DDR Perf hardware feature */
+#define DDR_CAP_AXI_ID_FILTER          0x1     /* support AXI ID filter */
+
+struct fsl_ddr_devtype_data {
+       unsigned int quirks;    /* quirks needed for different DDR Perf core */
+};
+
+static const struct fsl_ddr_devtype_data imx8_devtype_data;
+
+static const struct fsl_ddr_devtype_data imx8m_devtype_data = {
+       .quirks = DDR_CAP_AXI_ID_FILTER,
+};
+
 static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
-       { .compatible = "fsl,imx8-ddr-pmu",},
-       { .compatible = "fsl,imx8m-ddr-pmu",},
+       { .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data},
+       { .compatible = "fsl,imx8m-ddr-pmu", .data = &imx8m_devtype_data},
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, imx_ddr_pmu_dt_ids);
 
 struct ddr_pmu {
        struct pmu pmu;
@@ -57,6 +73,7 @@ struct ddr_pmu {
        struct perf_event *events[NUM_COUNTERS];
        int active_events;
        enum cpuhp_state cpuhp_state;
+       const struct fsl_ddr_devtype_data *devtype_data;
        int irq;
        int id;
 };
@@ -128,6 +145,8 @@ static struct attribute *ddr_perf_events_attrs[] = {
        IMX8_DDR_PMU_EVENT_ATTR(refresh, 0x37),
        IMX8_DDR_PMU_EVENT_ATTR(write, 0x38),
        IMX8_DDR_PMU_EVENT_ATTR(raw-hazard, 0x39),
+       IMX8_DDR_PMU_EVENT_ATTR(axid-read, 0x41),
+       IMX8_DDR_PMU_EVENT_ATTR(axid-write, 0x42),
        NULL,
 };
 
@@ -137,9 +156,13 @@ static struct attribute_group ddr_perf_events_attr_group = {
 };
 
 PMU_FORMAT_ATTR(event, "config:0-7");
+PMU_FORMAT_ATTR(axi_id, "config1:0-15");
+PMU_FORMAT_ATTR(axi_mask, "config1:16-31");
 
 static struct attribute *ddr_perf_format_attrs[] = {
        &format_attr_event.attr,
+       &format_attr_axi_id.attr,
+       &format_attr_axi_mask.attr,
        NULL,
 };
 
@@ -189,6 +212,26 @@ static u32 ddr_perf_read_counter(struct ddr_pmu *pmu, int counter)
        return readl_relaxed(pmu->base + COUNTER_READ + counter * 4);
 }
 
+static bool ddr_perf_is_filtered(struct perf_event *event)
+{
+       return event->attr.config == 0x41 || event->attr.config == 0x42;
+}
+
+static u32 ddr_perf_filter_val(struct perf_event *event)
+{
+       return event->attr.config1;
+}
+
+static bool ddr_perf_filters_compatible(struct perf_event *a,
+                                       struct perf_event *b)
+{
+       if (!ddr_perf_is_filtered(a))
+               return true;
+       if (!ddr_perf_is_filtered(b))
+               return true;
+       return ddr_perf_filter_val(a) == ddr_perf_filter_val(b);
+}
+
 static int ddr_perf_event_init(struct perf_event *event)
 {
        struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
@@ -215,6 +258,15 @@ static int ddr_perf_event_init(struct perf_event *event)
                        !is_software_event(event->group_leader))
                return -EINVAL;
 
+       if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
+               if (!ddr_perf_filters_compatible(event, event->group_leader))
+                       return -EINVAL;
+               for_each_sibling_event(sibling, event->group_leader) {
+                       if (!ddr_perf_filters_compatible(event, sibling))
+                               return -EINVAL;
+               }
+       }
+
        for_each_sibling_event(sibling, event->group_leader) {
                if (sibling->pmu != event->pmu &&
                                !is_software_event(sibling))
@@ -287,6 +339,23 @@ static int ddr_perf_event_add(struct perf_event *event, int flags)
        struct hw_perf_event *hwc = &event->hw;
        int counter;
        int cfg = event->attr.config;
+       int cfg1 = event->attr.config1;
+
+       if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
+               int i;
+
+               for (i = 1; i < NUM_COUNTERS; i++) {
+                       if (pmu->events[i] &&
+                           !ddr_perf_filters_compatible(event, pmu->events[i]))
+                               return -EINVAL;
+               }
+
+               if (ddr_perf_is_filtered(event)) {
+                       /* revert axi id masking(axi_mask) value */
+                       cfg1 ^= AXI_MASKING_REVERT;
+                       writel(cfg1, pmu->base + COUNTER_DPCR1);
+               }
+       }
 
        counter = ddr_perf_alloc_counter(pmu, cfg);
        if (counter < 0) {
@@ -472,6 +541,8 @@ static int ddr_perf_probe(struct platform_device *pdev)
        if (!name)
                return -ENOMEM;
 
+       pmu->devtype_data = of_device_get_match_data(&pdev->dev);
+
        pmu->cpu = raw_smp_processor_id();
        ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
                                      DDR_CPUHP_CB_NAME,
index 6ad0823..e42d446 100644 (file)
@@ -217,10 +217,8 @@ static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu,
 
        /* Read and init IRQ */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "DDRC PMU get irq fail; irq:%d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr,
                               IRQF_NOBALANCING | IRQF_NO_THREAD,
index 4f2917f..f280638 100644 (file)
@@ -207,10 +207,8 @@ static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu,
 
        /* Read and init IRQ */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "HHA PMU get irq fail; irq:%d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr,
                              IRQF_NOBALANCING | IRQF_NO_THREAD,
index 9153e09..078b8dc 100644 (file)
@@ -206,10 +206,8 @@ static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
 
        /* Read and init IRQ */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "L3C PMU get irq fail; irq:%d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
                               IRQF_NOBALANCING | IRQF_NO_THREAD,
index d06182f..21d6991 100644 (file)
@@ -909,12 +909,8 @@ static int l2_cache_pmu_probe_cluster(struct device *dev, void *data)
        cluster->cluster_id = fw_cluster_id;
 
        irq = platform_get_irq(sdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev,
-                       "Failed to get valid irq for cluster %ld\n",
-                       fw_cluster_id);
+       if (irq < 0)
                return irq;
-       }
        irq_set_status_flags(irq, IRQ_NOAUTOEN);
        cluster->irq = irq;
 
index 3259e2e..7e328d6 100644 (file)
@@ -1901,10 +1901,8 @@ static int xgene_pmu_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "No IRQ resource\n");
+       if (irq < 0)
                return -EINVAL;
-       }
 
        rc = devm_request_irq(&pdev->dev, irq, xgene_pmu_isr,
                                IRQF_NOBALANCING | IRQF_NO_THREAD,
index ba6438a..ff84d1a 100644 (file)
@@ -2552,7 +2552,7 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
                        if (IS_ERR(map))
                                return map;
                } else
-                       map = ERR_PTR(-ENODEV);
+                       return ERR_PTR(-ENODEV);
 
                ctx->maps[ASPEED_IP_LPC] = map;
                dev_dbg(ctx->dev, "Acquired LPC regmap");
@@ -2562,6 +2562,33 @@ static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
        return ERR_PTR(-EINVAL);
 }
 
+static int aspeed_g5_sig_expr_eval(struct aspeed_pinmux_data *ctx,
+                                  const struct aspeed_sig_expr *expr,
+                                  bool enabled)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < expr->ndescs; i++) {
+               const struct aspeed_sig_desc *desc = &expr->descs[i];
+               struct regmap *map;
+
+               map = aspeed_g5_acquire_regmap(ctx, desc->ip);
+               if (IS_ERR(map)) {
+                       dev_err(ctx->dev,
+                               "Failed to acquire regmap for IP block %d\n",
+                               desc->ip);
+                       return PTR_ERR(map);
+               }
+
+               ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]);
+               if (ret <= 0)
+                       return ret;
+       }
+
+       return 1;
+}
+
 /**
  * Configure a pin's signal by applying an expression's descriptor state for
  * all descriptors in the expression.
@@ -2647,6 +2674,7 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx,
 }
 
 static const struct aspeed_pinmux_ops aspeed_g5_ops = {
+       .eval = aspeed_g5_sig_expr_eval,
        .set = aspeed_g5_sig_expr_set,
 };
 
index 839c01b..57305ca 100644 (file)
@@ -78,11 +78,14 @@ int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
  * neither the enabled nor disabled state. Thus we must explicitly test for
  * either condition as required.
  */
-int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+int aspeed_sig_expr_eval(struct aspeed_pinmux_data *ctx,
                         const struct aspeed_sig_expr *expr, bool enabled)
 {
-       int i;
        int ret;
+       int i;
+
+       if (ctx->ops->eval)
+               return ctx->ops->eval(ctx, expr, enabled);
 
        for (i = 0; i < expr->ndescs; i++) {
                const struct aspeed_sig_desc *desc = &expr->descs[i];
index 52d299b..db3457c 100644 (file)
@@ -702,6 +702,8 @@ struct aspeed_pin_function {
 struct aspeed_pinmux_data;
 
 struct aspeed_pinmux_ops {
+       int (*eval)(struct aspeed_pinmux_data *ctx,
+                   const struct aspeed_sig_expr *expr, bool enabled);
        int (*set)(struct aspeed_pinmux_data *ctx,
                   const struct aspeed_sig_expr *expr, bool enabled);
 };
@@ -722,9 +724,8 @@ struct aspeed_pinmux_data {
 int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled,
                         struct regmap *map);
 
-int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
-                        const struct aspeed_sig_expr *expr,
-                        bool enabled);
+int aspeed_sig_expr_eval(struct aspeed_pinmux_data *ctx,
+                        const struct aspeed_sig_expr *expr, bool enabled);
 
 static inline int aspeed_sig_expr_set(struct aspeed_pinmux_data *ctx,
                                      const struct aspeed_sig_expr *expr,
index e5a112a..297b7b5 100644 (file)
@@ -1455,6 +1455,20 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
        chip->irq_eoi(data);
 }
 
+static void byt_init_irq_valid_mask(struct gpio_chip *chip,
+                                   unsigned long *valid_mask,
+                                   unsigned int ngpios)
+{
+       /*
+        * FIXME: currently the valid_mask is filled in as part of
+        * initializing the irq_chip below in byt_gpio_irq_init_hw().
+        * when converting this driver to the new way of passing the
+        * gpio_irq_chip along when adding the gpio_chip, move the
+        * mask initialization into this callback instead. Right now
+        * this callback is here to make sure the mask gets allocated.
+        */
+}
+
 static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 {
        struct gpio_chip *gc = &vg->chip;
@@ -1525,7 +1539,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
        gc->can_sleep   = false;
        gc->parent      = &vg->pdev->dev;
        gc->ngpio       = vg->soc_data->npins;
-       gc->irq.need_valid_mask = true;
+       gc->irq.init_valid_mask = byt_init_irq_valid_mask;
 
 #ifdef CONFIG_PM_SLEEP
        vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
index 03ec7a5..ab681d1 100644 (file)
@@ -1543,6 +1543,30 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
        {}
 };
 
+static void chv_init_irq_valid_mask(struct gpio_chip *chip,
+                                   unsigned long *valid_mask,
+                                   unsigned int ngpios)
+{
+       struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct chv_community *community = pctrl->community;
+       int i;
+
+       /* Do not add GPIOs that can only generate GPEs to the IRQ domain */
+       for (i = 0; i < community->npins; i++) {
+               const struct pinctrl_pin_desc *desc;
+               u32 intsel;
+
+               desc = &community->pins[i];
+
+               intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
+               intsel &= CHV_PADCTRL0_INTSEL_MASK;
+               intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+               if (intsel >= community->nirqs)
+                       clear_bit(i, valid_mask);
+       }
+}
+
 static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 {
        const struct chv_gpio_pinrange *range;
@@ -1557,7 +1581,8 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
        chip->label = dev_name(pctrl->dev);
        chip->parent = pctrl->dev;
        chip->base = -1;
-       chip->irq.need_valid_mask = need_valid_mask;
+       if (need_valid_mask)
+               chip->irq.init_valid_mask = chv_init_irq_valid_mask;
 
        ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
        if (ret) {
@@ -1576,21 +1601,6 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
                }
        }
 
-       /* Do not add GPIOs that can only generate GPEs to the IRQ domain */
-       for (i = 0; i < community->npins; i++) {
-               const struct pinctrl_pin_desc *desc;
-               u32 intsel;
-
-               desc = &community->pins[i];
-
-               intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
-               intsel &= CHV_PADCTRL0_INTSEL_MASK;
-               intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
-
-               if (need_valid_mask && intsel >= community->nirqs)
-                       clear_bit(i, chip->irq.valid_mask);
-       }
-
        /*
         * The same set of machines in chv_no_valid_mask[] have incorrectly
         * configured GPIOs that generate spurious interrupts so we use
index d3332da..dd5aa9a 100644 (file)
@@ -585,12 +585,24 @@ static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl)
        return stmfx_function_enable(pctl->stmfx, func);
 }
 
+static int stmfx_pinctrl_gpio_init_valid_mask(struct gpio_chip *gc,
+                                             unsigned long *valid_mask,
+                                             unsigned int ngpios)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 n;
+
+       for_each_clear_bit(n, &pctl->gpio_valid_mask, ngpios)
+               clear_bit(n, valid_mask);
+
+       return 0;
+}
+
 static int stmfx_pinctrl_probe(struct platform_device *pdev)
 {
        struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent);
        struct device_node *np = pdev->dev.of_node;
        struct stmfx_pinctrl *pctl;
-       u32 n;
        int irq, ret;
 
        pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL);
@@ -650,7 +662,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
        pctl->gpio_chip.ngpio = pctl->pctl_desc.npins;
        pctl->gpio_chip.can_sleep = true;
        pctl->gpio_chip.of_node = np;
-       pctl->gpio_chip.need_valid_mask = true;
+       pctl->gpio_chip.init_valid_mask = stmfx_pinctrl_gpio_init_valid_mask;
 
        ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
        if (ret) {
@@ -668,8 +680,6 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
        pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type;
        pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock;
        pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock;
-       for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio)
-               clear_bit(n, pctl->gpio_chip.valid_mask);
 
        ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip,
                                          0, handle_bad_irq, IRQ_TYPE_NONE);
index 8e14a5f..fa2c878 100644 (file)
@@ -138,6 +138,7 @@ config PINCTRL_QCOM_SPMI_PMIC
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
index 7f35c19..b8a1c43 100644 (file)
@@ -593,24 +593,25 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #define msm_gpio_dbg_show NULL
 #endif
 
-static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
+static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
+                                   unsigned long *valid_mask,
+                                   unsigned int ngpios)
 {
-       struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        int ret;
        unsigned int len, i;
-       unsigned int max_gpios = pctrl->soc->ngpios;
        const int *reserved = pctrl->soc->reserved_gpios;
        u16 *tmp;
 
        /* Driver provided reserved list overrides DT and ACPI */
        if (reserved) {
-               bitmap_fill(chip->valid_mask, max_gpios);
+               bitmap_fill(valid_mask, ngpios);
                for (i = 0; reserved[i] >= 0; i++) {
-                       if (i >= max_gpios || reserved[i] >= max_gpios) {
+                       if (i >= ngpios || reserved[i] >= ngpios) {
                                dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
                                return -EINVAL;
                        }
-                       clear_bit(reserved[i], chip->valid_mask);
+                       clear_bit(reserved[i], valid_mask);
                }
 
                return 0;
@@ -622,7 +623,7 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
        if (ret < 0)
                return 0;
 
-       if (ret > max_gpios)
+       if (ret > ngpios)
                return -EINVAL;
 
        tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
@@ -635,9 +636,9 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
                goto out;
        }
 
-       bitmap_zero(chip->valid_mask, max_gpios);
+       bitmap_zero(valid_mask, ngpios);
        for (i = 0; i < len; i++)
-               set_bit(tmp[i], chip->valid_mask);
+               set_bit(tmp[i], valid_mask);
 
 out:
        kfree(tmp);
@@ -653,7 +654,6 @@ static const struct gpio_chip msm_gpio_template = {
        .request          = gpiochip_generic_request,
        .free             = gpiochip_generic_free,
        .dbg_show         = msm_gpio_dbg_show,
-       .init_valid_mask  = msm_gpio_init_valid_mask,
 };
 
 /* For dual-edge interrupts in software, since some hardware has no
@@ -1015,7 +1015,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        chip->parent = pctrl->dev;
        chip->owner = THIS_MODULE;
        chip->of_node = pctrl->dev->of_node;
-       chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
+       if (msm_gpio_needs_valid_mask(pctrl))
+               chip->init_valid_mask = msm_gpio_init_valid_mask;
 
        pctrl->irq_chip.name = "msmgpio";
        pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
index f39da87..442db15 100644 (file)
@@ -170,8 +170,6 @@ struct pmic_gpio_state {
        struct regmap   *map;
        struct pinctrl_dev *ctrl;
        struct gpio_chip chip;
-       struct fwnode_handle *fwnode;
-       struct irq_domain *domain;
 };
 
 static const struct pinconf_generic_params pmic_gpio_bindings[] = {
@@ -751,23 +749,6 @@ static int pmic_gpio_of_xlate(struct gpio_chip *chip,
        return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
 }
 
-static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
-{
-       struct pmic_gpio_state *state = gpiochip_get_data(chip);
-       struct irq_fwspec fwspec;
-
-       fwspec.fwnode = state->fwnode;
-       fwspec.param_count = 2;
-       fwspec.param[0] = pin + PMIC_GPIO_PHYSICAL_OFFSET;
-       /*
-        * Set the type to a safe value temporarily. This will be overwritten
-        * later with the proper value by irq_set_type.
-        */
-       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
-
-       return irq_create_fwspec_mapping(&fwspec);
-}
-
 static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        struct pmic_gpio_state *state = gpiochip_get_data(chip);
@@ -787,7 +768,6 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
        .request                = gpiochip_generic_request,
        .free                   = gpiochip_generic_free,
        .of_xlate               = pmic_gpio_of_xlate,
-       .to_irq                 = pmic_gpio_to_irq,
        .dbg_show               = pmic_gpio_dbg_show,
 };
 
@@ -964,46 +944,24 @@ static int pmic_gpio_domain_translate(struct irq_domain *domain,
        return 0;
 }
 
-static int pmic_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
-                                 unsigned int nr_irqs, void *data)
+static unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip,
+                                                 unsigned int offset)
 {
-       struct pmic_gpio_state *state = container_of(domain->host_data,
-                                                    struct pmic_gpio_state,
-                                                    chip);
-       struct irq_fwspec *fwspec = data;
-       struct irq_fwspec parent_fwspec;
-       irq_hw_number_t hwirq;
-       unsigned int type;
-       int ret, i;
-
-       ret = pmic_gpio_domain_translate(domain, fwspec, &hwirq, &type);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < nr_irqs; i++)
-               irq_domain_set_info(domain, virq + i, hwirq + i,
-                                   &pmic_gpio_irq_chip, state,
-                                   handle_level_irq, NULL, NULL);
+       return offset + PMIC_GPIO_PHYSICAL_OFFSET;
+}
 
-       parent_fwspec.fwnode = domain->parent->fwnode;
-       parent_fwspec.param_count = 4;
-       parent_fwspec.param[0] = 0;
-       parent_fwspec.param[1] = hwirq + 0xc0;
-       parent_fwspec.param[2] = 0;
-       parent_fwspec.param[3] = fwspec->param[1];
+static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
+                                          unsigned int child_hwirq,
+                                          unsigned int child_type,
+                                          unsigned int *parent_hwirq,
+                                          unsigned int *parent_type)
+{
+       *parent_hwirq = child_hwirq + 0xc0;
+       *parent_type = child_type;
 
-       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
-                                           &parent_fwspec);
+       return 0;
 }
 
-static const struct irq_domain_ops pmic_gpio_domain_ops = {
-       .activate = gpiochip_irq_domain_activate,
-       .alloc = pmic_gpio_domain_alloc,
-       .deactivate = gpiochip_irq_domain_deactivate,
-       .free = irq_domain_free_irqs_common,
-       .translate = pmic_gpio_domain_translate,
-};
-
 static int pmic_gpio_probe(struct platform_device *pdev)
 {
        struct irq_domain *parent_domain;
@@ -1013,6 +971,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
        struct pinctrl_desc *pctrldesc;
        struct pmic_gpio_pad *pad, *pads;
        struct pmic_gpio_state *state;
+       struct gpio_irq_chip *girq;
        int ret, npins, i;
        u32 reg;
 
@@ -1092,19 +1051,21 @@ static int pmic_gpio_probe(struct platform_device *pdev)
        if (!parent_domain)
                return -ENXIO;
 
-       state->fwnode = of_node_to_fwnode(state->dev->of_node);
-       state->domain = irq_domain_create_hierarchy(parent_domain, 0,
-                                                   state->chip.ngpio,
-                                                   state->fwnode,
-                                                   &pmic_gpio_domain_ops,
-                                                   &state->chip);
-       if (!state->domain)
-               return -ENODEV;
+       girq = &state->chip.irq;
+       girq->chip = &pmic_gpio_irq_chip;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
+       girq->fwnode = of_node_to_fwnode(state->dev->of_node);
+       girq->parent_domain = parent_domain;
+       girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
+       girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
+       girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq;
+       girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate;
 
        ret = gpiochip_add_data(&state->chip, state);
        if (ret) {
                dev_err(state->dev, "can't add gpio chip\n");
-               goto err_chip_add_data;
+               return ret;
        }
 
        /*
@@ -1130,8 +1091,6 @@ static int pmic_gpio_probe(struct platform_device *pdev)
 
 err_range:
        gpiochip_remove(&state->chip);
-err_chip_add_data:
-       irq_domain_remove(state->domain);
        return ret;
 }
 
@@ -1140,7 +1099,6 @@ static int pmic_gpio_remove(struct platform_device *pdev)
        struct pmic_gpio_state *state = platform_get_drvdata(pdev);
 
        gpiochip_remove(&state->chip);
-       irq_domain_remove(state->domain);
        return 0;
 }
 
index e504d25..430731c 100644 (file)
@@ -707,7 +707,7 @@ static int cros_ec_ishtp_reset(struct ishtp_cl_device *cl_device)
  */
 static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
 
@@ -722,7 +722,7 @@ static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
  */
 static int __maybe_unused cros_ec_ishtp_resume(struct device *device)
 {
-       struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+       struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
        struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
        struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
 
index 006a8ff..714306b 100644 (file)
@@ -706,7 +706,7 @@ static int cros_ec_spi_devm_high_pri_alloc(struct device *dev,
                                           struct cros_ec_spi *ec_spi)
 {
        struct sched_param sched_priority = {
-               .sched_priority = MAX_RT_PRIO - 1,
+               .sched_priority = MAX_RT_PRIO / 2,
        };
        int err;
 
index d9542c6..f57bbbe 100644 (file)
@@ -152,6 +152,13 @@ static const struct x86_cpu_id int0002_cpu_ids[] = {
        {}
 };
 
+static void int0002_init_irq_valid_mask(struct gpio_chip *chip,
+                                       unsigned long *valid_mask,
+                                       unsigned int ngpios)
+{
+       bitmap_clear(valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
+}
+
 static int int0002_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -184,7 +191,7 @@ static int int0002_probe(struct platform_device *pdev)
        chip->direction_output = int0002_gpio_direction_output;
        chip->base = -1;
        chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1;
-       chip->irq.need_valid_mask = true;
+       chip->irq.init_valid_mask = int0002_init_irq_valid_mask;
 
        ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
        if (ret) {
@@ -192,8 +199,6 @@ static int int0002_probe(struct platform_device *pdev)
                return ret;
        }
 
-       bitmap_clear(chip->irq.valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
-
        /*
         * We manually request the irq here instead of passing a flow-handler
         * to gpiochip_set_chained_irqchip, because the irq is shared.
index 30de448..86d88ae 100644 (file)
@@ -742,6 +742,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
                                                USB_CH_IP_CUR_LVL_1P5;
                        break;
                }
+               /* Else, fall through */
        case USB_STAT_HM_IDGND:
                dev_err(di->dev, "USB Type - Charging not allowed\n");
                di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
index ef6777e..6f0404f 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_RAS)      += ras.o debugfs.o
+obj-$(CONFIG_RAS)      += ras.o
+obj-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_RAS_CEC)  += cec.o
index 5d54580..c09cf55 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/mm.h>
 #include <linux/gfp.h>
+#include <linux/ras.h>
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
 
index 9c1b717..0d4f985 100644 (file)
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/debugfs.h>
+#include <linux/ras.h>
+#include "debugfs.h"
 
 struct dentry *ras_debugfs_dir;
 
index b57093d..3ee6353 100644 (file)
@@ -83,6 +83,7 @@ config REGULATOR_88PM8607
 config REGULATOR_ACT8865
        tristate "Active-semi act8865 voltage regulator"
        depends on I2C
+       depends on POWER_SUPPLY
        select REGMAP_I2C
        help
          This driver controls a active-semi act8865 voltage output
@@ -618,6 +619,15 @@ config REGULATOR_MT6323
          This driver supports the control of different power rails of device
          through regulator interface.
 
+config REGULATOR_MT6358
+       tristate "MediaTek MT6358 PMIC"
+       depends on MFD_MT6397 && BROKEN
+       help
+         Say y here to select this option to enable the power regulator of
+         MediaTek MT6358 PMIC.
+         This driver supports the control of different power rails of device
+         through regulator interface.
+
 config REGULATOR_MT6380
        tristate "MediaTek MT6380 PMIC"
        depends on MTK_PMIC_WRAP
@@ -906,6 +916,13 @@ config REGULATOR_SY8106A
        help
          This driver supports SY8106A single output regulator.
 
+config REGULATOR_SY8824X
+       tristate "Silergy SY8824C/SY8824E regulator"
+       depends on I2C && (OF || COMPILE_TEST)
+       select REGMAP_I2C
+       help
+         This driver supports SY8824C single output regulator.
+
 config REGULATOR_TPS51632
        tristate "TI TPS51632 Power Regulator"
        depends on I2C
index eef73b5..2210ba5 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
+obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
@@ -111,6 +112,7 @@ obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
 obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
+obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
index cf72d7c..0fa97f9 100644 (file)
 #include <linux/regulator/act8865.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/power_supply.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regmap.h>
+#include <dt-bindings/regulator/active-semi,8865-regulator.h>
 
 /*
  * ACT8600 Global Register Map.
  */
 #define        ACT8865_SYS_MODE        0x00
 #define        ACT8865_SYS_CTRL        0x01
+#define        ACT8865_SYS_UNLK_REGS   0x0b
 #define        ACT8865_DCDC1_VSET1     0x20
 #define        ACT8865_DCDC1_VSET2     0x21
 #define        ACT8865_DCDC1_CTRL      0x22
+#define        ACT8865_DCDC1_SUS       0x24
 #define        ACT8865_DCDC2_VSET1     0x30
 #define        ACT8865_DCDC2_VSET2     0x31
 #define        ACT8865_DCDC2_CTRL      0x32
+#define        ACT8865_DCDC2_SUS       0x34
 #define        ACT8865_DCDC3_VSET1     0x40
 #define        ACT8865_DCDC3_VSET2     0x41
 #define        ACT8865_DCDC3_CTRL      0x42
+#define        ACT8865_DCDC3_SUS       0x44
 #define        ACT8865_LDO1_VSET       0x50
 #define        ACT8865_LDO1_CTRL       0x51
+#define        ACT8865_LDO1_SUS        0x52
 #define        ACT8865_LDO2_VSET       0x54
 #define        ACT8865_LDO2_CTRL       0x55
+#define        ACT8865_LDO2_SUS        0x56
 #define        ACT8865_LDO3_VSET       0x60
 #define        ACT8865_LDO3_CTRL       0x61
+#define        ACT8865_LDO3_SUS        0x62
 #define        ACT8865_LDO4_VSET       0x64
 #define        ACT8865_LDO4_CTRL       0x65
+#define        ACT8865_LDO4_SUS        0x66
 #define        ACT8865_MSTROFF         0x20
 
 /*
  * Field Definitions.
  */
 #define        ACT8865_ENA             0x80    /* ON - [7] */
+#define        ACT8865_DIS             0x40    /* DIS - [6] */
+
 #define        ACT8865_VSEL_MASK       0x3F    /* VSET - [5:0] */
 
 
 #define ACT8600_LDO10_ENA              0x40    /* ON - [6] */
 #define ACT8600_SUDCDC_VSEL_MASK       0xFF    /* SUDCDC VSET - [7:0] */
 
+#define ACT8600_APCH_CHG_ACIN          BIT(7)
+#define ACT8600_APCH_CHG_USB           BIT(6)
+#define ACT8600_APCH_CSTATE0           BIT(5)
+#define ACT8600_APCH_CSTATE1           BIT(4)
+
 /*
  * ACT8865 voltage number
  */
@@ -217,6 +234,171 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0),
 };
 
+static int act8865_set_suspend_state(struct regulator_dev *rdev, bool enable)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev->desc->id, reg, val;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_SUS;
+               val = 0xa8;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_SUS;
+               val = 0xe8;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_SUS;
+               val = 0xe8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (enable)
+               val |= BIT(4);
+
+       /*
+        * Ask the PMIC to enable/disable this output when entering hibernate
+        * mode.
+        */
+       return regmap_write(regmap, reg, val);
+}
+
+static int act8865_set_suspend_enable(struct regulator_dev *rdev)
+{
+       return act8865_set_suspend_state(rdev, true);
+}
+
+static int act8865_set_suspend_disable(struct regulator_dev *rdev)
+{
+       return act8865_set_suspend_state(rdev, false);
+}
+
+static unsigned int act8865_of_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case ACT8865_REGULATOR_MODE_FIXED:
+               return REGULATOR_MODE_FAST;
+       case ACT8865_REGULATOR_MODE_NORMAL:
+               return REGULATOR_MODE_NORMAL;
+       case ACT8865_REGULATOR_MODE_LOWPOWER:
+               return REGULATOR_MODE_STANDBY;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static int act8865_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev_get_id(rdev);
+       int reg, val = 0;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_CTRL;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_CTRL;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_CTRL;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_CTRL;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_CTRL;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_CTRL;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_CTRL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+       case REGULATOR_MODE_NORMAL:
+               if (id <= ACT8865_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               if (id > ACT8865_ID_DCDC3)
+                       val = BIT(5);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(regmap, reg, BIT(5), val);
+}
+
+static unsigned int act8865_get_mode(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev->regmap;
+       int id = rdev_get_id(rdev);
+       int reg, ret, val = 0;
+
+       switch (id) {
+       case ACT8865_ID_DCDC1:
+               reg = ACT8865_DCDC1_CTRL;
+               break;
+       case ACT8865_ID_DCDC2:
+               reg = ACT8865_DCDC2_CTRL;
+               break;
+       case ACT8865_ID_DCDC3:
+               reg = ACT8865_DCDC3_CTRL;
+               break;
+       case ACT8865_ID_LDO1:
+               reg = ACT8865_LDO1_CTRL;
+               break;
+       case ACT8865_ID_LDO2:
+               reg = ACT8865_LDO2_CTRL;
+               break;
+       case ACT8865_ID_LDO3:
+               reg = ACT8865_LDO3_CTRL;
+               break;
+       case ACT8865_ID_LDO4:
+               reg = ACT8865_LDO4_CTRL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_read(regmap, reg, &val);
+       if (ret)
+               return ret;
+
+       if (id <= ACT8865_ID_DCDC3 && (val & BIT(5)))
+               return REGULATOR_MODE_FAST;
+       else if (id > ACT8865_ID_DCDC3 && !(val & BIT(5)))
+               return REGULATOR_MODE_NORMAL;
+       else
+               return REGULATOR_MODE_STANDBY;
+}
+
 static const struct regulator_ops act8865_ops = {
        .list_voltage           = regulator_list_voltage_linear_range,
        .map_voltage            = regulator_map_voltage_linear_range,
@@ -224,24 +406,44 @@ static const struct regulator_ops act8865_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
+       .set_mode               = act8865_set_mode,
+       .get_mode               = act8865_get_mode,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_enable     = act8865_set_suspend_enable,
+       .set_suspend_disable    = act8865_set_suspend_disable,
 };
 
 static const struct regulator_ops act8865_ldo_ops = {
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .set_mode               = act8865_set_mode,
+       .get_mode               = act8865_get_mode,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_enable     = act8865_set_suspend_enable,
+       .set_suspend_disable    = act8865_set_suspend_disable,
+       .set_pull_down          = regulator_set_pull_down_regmap,
+};
+
+static const struct regulator_ops act8865_fixed_ldo_ops = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
 };
 
-#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply)           \
+#define ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, _ops)    \
        [_family##_ID_##_id] = {                                        \
                .name                   = _name,                        \
                .of_match               = of_match_ptr(_name),          \
+               .of_map_mode            = act8865_of_map_mode,          \
                .regulators_node        = of_match_ptr("regulators"),   \
                .supply_name            = _supply,                      \
                .id                     = _family##_ID_##_id,           \
                .type                   = REGULATOR_VOLTAGE,            \
-               .ops                    = &act8865_ops,                 \
+               .ops                    = _ops,                         \
                .n_voltages             = ACT8865_VOLTAGE_NUM,          \
                .linear_ranges          = act8865_voltage_ranges,       \
                .n_linear_ranges        = ARRAY_SIZE(act8865_voltage_ranges), \
@@ -249,9 +451,17 @@ static const struct regulator_ops act8865_ldo_ops = {
                .vsel_mask              = ACT8865_VSEL_MASK,            \
                .enable_reg             = _family##_##_id##_CTRL,       \
                .enable_mask            = ACT8865_ENA,                  \
+               .pull_down_reg          = _family##_##_id##_CTRL,       \
+               .pull_down_mask         = ACT8865_DIS,                  \
                .owner                  = THIS_MODULE,                  \
        }
 
+#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \
+       ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ops)
+
+#define ACT88xx_LDO(_name, _family, _id, _vsel_reg, _supply) \
+       ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ldo_ops)
+
 static const struct regulator_desc act8600_regulators[] = {
        ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"),
        ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"),
@@ -281,7 +491,7 @@ static const struct regulator_desc act8600_regulators[] = {
                .of_match = of_match_ptr("LDO_REG9"),
                .regulators_node = of_match_ptr("regulators"),
                .id = ACT8600_ID_LDO9,
-               .ops = &act8865_ldo_ops,
+               .ops = &act8865_fixed_ldo_ops,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = 1,
                .fixed_uV = 3300000,
@@ -294,7 +504,7 @@ static const struct regulator_desc act8600_regulators[] = {
                .of_match = of_match_ptr("LDO_REG10"),
                .regulators_node = of_match_ptr("regulators"),
                .id = ACT8600_ID_LDO10,
-               .ops = &act8865_ldo_ops,
+               .ops = &act8865_fixed_ldo_ops,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = 1,
                .fixed_uV = 1200000,
@@ -323,20 +533,20 @@ static const struct regulator_desc act8865_regulators[] = {
        ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"),
        ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"),
        ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"),
-       ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
-       ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
 };
 
 static const struct regulator_desc act8865_alt_regulators[] = {
        ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"),
        ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"),
        ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"),
-       ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
-       ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
-       ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
+       ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
+       ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
 };
 
 #ifdef CONFIG_OF
@@ -372,6 +582,75 @@ static void act8865_power_off(void)
        while (1);
 }
 
+static int act8600_charger_get_status(struct regmap *map)
+{
+       unsigned int val;
+       int ret;
+       u8 state0, state1;
+
+       ret = regmap_read(map, ACT8600_APCH_STAT, &val);
+       if (ret < 0)
+               return ret;
+
+       state0 = val & ACT8600_APCH_CSTATE0;
+       state1 = val & ACT8600_APCH_CSTATE1;
+
+       if (state0 && !state1)
+               return POWER_SUPPLY_STATUS_CHARGING;
+       if (!state0 && state1)
+               return POWER_SUPPLY_STATUS_NOT_CHARGING;
+       if (!state0 && !state1)
+               return POWER_SUPPLY_STATUS_DISCHARGING;
+
+       return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static int act8600_charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct regmap *map = power_supply_get_drvdata(psy);
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = act8600_charger_get_status(map);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum power_supply_property act8600_charger_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+};
+
+static const struct power_supply_desc act8600_charger_desc = {
+       .name = "act8600-charger",
+       .type = POWER_SUPPLY_TYPE_BATTERY,
+       .properties = act8600_charger_properties,
+       .num_properties = ARRAY_SIZE(act8600_charger_properties),
+       .get_property = act8600_charger_get_property,
+};
+
+static int act8600_charger_probe(struct device *dev, struct regmap *regmap)
+{
+       struct power_supply *charger;
+       struct power_supply_config cfg = {
+               .drv_data = regmap,
+               .of_node = dev->of_node,
+       };
+
+       charger = devm_power_supply_register(dev, &act8600_charger_desc, &cfg);
+
+       return PTR_ERR_OR_ZERO(charger);
+}
+
 static int act8865_pmic_probe(struct i2c_client *client,
                              const struct i2c_device_id *i2c_id)
 {
@@ -483,9 +762,20 @@ static int act8865_pmic_probe(struct i2c_client *client,
                }
        }
 
+       if (type == ACT8600) {
+               ret = act8600_charger_probe(dev, act8865->regmap);
+               if (ret < 0) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "Failed to probe charger");
+                       return ret;
+               }
+       }
+
        i2c_set_clientdata(client, act8865);
 
-       return 0;
+       /* Unlock expert registers for ACT8865. */
+       return type != ACT8865 ? 0 : regmap_write(act8865->regmap,
+                                                 ACT8865_SYS_UNLK_REGS, 0xef);
 }
 
 static const struct i2c_device_id act8865_ids[] = {
index 5842849..d2f804d 100644 (file)
@@ -169,16 +169,16 @@ static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
                reg = ACT8945A_DCDC3_CTRL;
                break;
        case ACT8945A_ID_LDO1:
-               reg = ACT8945A_LDO1_SUS;
+               reg = ACT8945A_LDO1_CTRL;
                break;
        case ACT8945A_ID_LDO2:
-               reg = ACT8945A_LDO2_SUS;
+               reg = ACT8945A_LDO2_CTRL;
                break;
        case ACT8945A_ID_LDO3:
-               reg = ACT8945A_LDO3_SUS;
+               reg = ACT8945A_LDO3_CTRL;
                break;
        case ACT8945A_ID_LDO4:
-               reg = ACT8945A_LDO4_SUS;
+               reg = ACT8945A_LDO4_CTRL;
                break;
        default:
                return -EINVAL;
index e0c0cf4..afe9447 100644 (file)
@@ -381,12 +381,16 @@ static struct device_node *of_get_child_regulator(struct device_node *parent,
                if (!regnode) {
                        regnode = of_get_child_regulator(child, prop_name);
                        if (regnode)
-                               return regnode;
+                               goto err_node_put;
                } else {
-                       return regnode;
+                       goto err_node_put;
                }
        }
        return NULL;
+
+err_node_put:
+       of_node_put(child);
+       return regnode;
 }
 
 /**
@@ -564,13 +568,15 @@ static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
-       ssize_t ret;
+       int uV;
 
        regulator_lock(rdev);
-       ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev));
+       uV = regulator_get_voltage_rdev(rdev);
        regulator_unlock(rdev);
 
-       return ret;
+       if (uV < 0)
+               return uV;
+       return sprintf(buf, "%d\n", uV);
 }
 static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
 
@@ -5640,7 +5646,7 @@ static int __init regulator_init(void)
 /* init early to allow our consumers to complete system booting */
 core_initcall(regulator_init);
 
-static int __init regulator_late_cleanup(struct device *dev, void *data)
+static int regulator_late_cleanup(struct device *dev, void *data)
 {
        struct regulator_dev *rdev = dev_to_rdev(dev);
        const struct regulator_ops *ops = rdev->desc->ops;
@@ -5689,17 +5695,8 @@ unlock:
        return 0;
 }
 
-static int __init regulator_init_complete(void)
+static void regulator_init_complete_work_function(struct work_struct *work)
 {
-       /*
-        * Since DT doesn't provide an idiomatic mechanism for
-        * enabling full constraints and since it's much more natural
-        * with DT to provide them just assume that a DT enabled
-        * system has full constraints.
-        */
-       if (of_have_populated_dt())
-               has_full_constraints = true;
-
        /*
         * Regulators may had failed to resolve their input supplies
         * when were registered, either because the input supply was
@@ -5717,6 +5714,35 @@ static int __init regulator_init_complete(void)
         */
        class_for_each_device(&regulator_class, NULL, NULL,
                              regulator_late_cleanup);
+}
+
+static DECLARE_DELAYED_WORK(regulator_init_complete_work,
+                           regulator_init_complete_work_function);
+
+static int __init regulator_init_complete(void)
+{
+       /*
+        * Since DT doesn't provide an idiomatic mechanism for
+        * enabling full constraints and since it's much more natural
+        * with DT to provide them just assume that a DT enabled
+        * system has full constraints.
+        */
+       if (of_have_populated_dt())
+               has_full_constraints = true;
+
+       /*
+        * We punt completion for an arbitrary amount of time since
+        * systems like distros will load many drivers from userspace
+        * so consumers might not always be ready yet, this is
+        * particularly an issue with laptops where this might bounce
+        * the display off then on.  Ideally we'd get a notification
+        * from userspace when this happens but we don't so just wait
+        * a bit and hope we waited long enough.  It'd be better if
+        * we'd only do this on systems that need it, and a kernel
+        * command line option might be useful.
+        */
+       schedule_delayed_work(&regulator_init_complete_work,
+                             msecs_to_jiffies(30000));
 
        return 0;
 }
index 2ffc646..56f3f72 100644 (file)
@@ -1032,10 +1032,8 @@ static int da9062_regulator_probe(struct platform_device *pdev)
 
        /* LDOs overcurrent event support */
        irq = platform_get_irq_byname(pdev, "LDO_LIM");
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ.\n");
+       if (irq < 0)
                return irq;
-       }
        regulators->irq_ldo_lim = irq;
 
        ret = devm_request_threaded_irq(&pdev->dev, irq,
index 02f8163..28b1b20 100644 (file)
@@ -863,10 +863,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)
 
        /* LDOs overcurrent event support */
        irq = platform_get_irq_byname(pdev, "LDO_LIM");
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Failed to get IRQ.\n");
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_threaded_irq(&pdev->dev, irq,
                                NULL, da9063_ldo_lim_event,
index 0309823..bf80748 100644 (file)
@@ -285,7 +285,7 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
                pdata->reg_node[n] = da9211_matches[i].of_node;
                pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
                                  da9211_matches[i].of_node,
-                                 "enable",
+                                 "enable-gpios",
                                  0,
                                  GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
                                  "da9211-enable");
index 999547d..d90a6fd 100644 (file)
 #include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
+#include <linux/clk.h>
+
 
 struct fixed_voltage_data {
        struct regulator_desc desc;
        struct regulator_dev *dev;
+
+       struct clk *enable_clock;
+       unsigned int clk_enable_counter;
 };
 
+struct fixed_dev_type {
+       bool has_enable_clock;
+};
+
+static const struct fixed_dev_type fixed_voltage_data = {
+       .has_enable_clock = false,
+};
+
+static const struct fixed_dev_type fixed_clkenable_data = {
+       .has_enable_clock = true,
+};
+
+static int reg_clock_enable(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       ret = clk_prepare_enable(priv->enable_clock);
+       if (ret)
+               return ret;
+
+       priv->clk_enable_counter++;
+
+       return ret;
+}
+
+static int reg_clock_disable(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+
+       clk_disable_unprepare(priv->enable_clock);
+       priv->clk_enable_counter--;
+
+       return 0;
+}
+
+static int reg_clock_is_enabled(struct regulator_dev *rdev)
+{
+       struct fixed_voltage_data *priv = rdev_get_drvdata(rdev);
+
+       return priv->clk_enable_counter > 0;
+}
+
 
 /**
  * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
@@ -84,10 +133,19 @@ of_get_fixed_voltage_config(struct device *dev,
 static struct regulator_ops fixed_voltage_ops = {
 };
 
+static struct regulator_ops fixed_voltage_clkenabled_ops = {
+       .enable = reg_clock_enable,
+       .disable = reg_clock_disable,
+       .is_enabled = reg_clock_is_enabled,
+};
+
 static int reg_fixed_voltage_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct fixed_voltage_config *config;
        struct fixed_voltage_data *drvdata;
+       const struct fixed_dev_type *drvtype =
+               of_match_device(dev->driver->of_match_table, dev)->data;
        struct regulator_config cfg = { };
        enum gpiod_flags gflags;
        int ret;
@@ -118,7 +176,18 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
        }
        drvdata->desc.type = REGULATOR_VOLTAGE;
        drvdata->desc.owner = THIS_MODULE;
-       drvdata->desc.ops = &fixed_voltage_ops;
+
+       if (drvtype->has_enable_clock) {
+               drvdata->desc.ops = &fixed_voltage_clkenabled_ops;
+
+               drvdata->enable_clock = devm_clk_get(dev, NULL);
+               if (IS_ERR(drvdata->enable_clock)) {
+                       dev_err(dev, "Cant get enable-clock from devicetree\n");
+                       return -ENOENT;
+               }
+       } else {
+               drvdata->desc.ops = &fixed_voltage_ops;
+       }
 
        drvdata->desc.enable_time = config->startup_delay;
 
@@ -191,8 +260,16 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 
 #if defined(CONFIG_OF)
 static const struct of_device_id fixed_of_match[] = {
-       { .compatible = "regulator-fixed", },
-       {},
+       {
+               .compatible = "regulator-fixed",
+               .data = &fixed_voltage_data,
+       },
+       {
+               .compatible = "regulator-fixed-clock",
+               .data = &fixed_clkenable_data,
+       },
+       {
+       },
 };
 MODULE_DEVICE_TABLE(of, fixed_of_match);
 #endif
index 4986cc5..ca3dc3f 100644 (file)
@@ -860,3 +860,24 @@ int regulator_get_current_limit_regmap(struct regulator_dev *rdev)
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(regulator_get_current_limit_regmap);
+
+/**
+ * regulator_bulk_set_supply_names - initialize the 'supply' fields in an array
+ *                                   of regulator_bulk_data structs
+ *
+ * @consumers: array of regulator_bulk_data entries to initialize
+ * @supply_names: array of supply name strings
+ * @num_supplies: number of supply names to initialize
+ *
+ * Note: the 'consumers' array must be the size of 'num_supplies'.
+ */
+void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                                    const char *const *supply_names,
+                                    unsigned int num_supplies)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_supplies; i++)
+               consumers[i].supply = supply_names[i];
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_set_supply_names);
index 5647e2f..4b9f618 100644 (file)
 
 /* LM3632 */
 #define LM3632_BOOST_VSEL_MAX          0x26
-#define LM3632_LDO_VSEL_MAX            0x29
+#define LM3632_LDO_VSEL_MAX            0x28
 #define LM3632_VBOOST_MIN              4500000
 #define LM3632_VLDO_MIN                        4000000
 
 /* LM36274 */
 #define LM36274_BOOST_VSEL_MAX         0x3f
-#define LM36274_LDO_VSEL_MAX           0x34
+#define LM36274_LDO_VSEL_MAX           0x32
 #define LM36274_VOLTAGE_MIN            4000000
 
 /* Common */
@@ -226,7 +226,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vboost",
                .id             = LM36274_BOOST,
                .ops            = &lm363x_boost_voltage_table_ops,
-               .n_voltages     = LM36274_BOOST_VSEL_MAX,
+               .n_voltages     = LM36274_BOOST_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
@@ -239,7 +239,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vpos",
                .id             = LM36274_LDO_POS,
                .ops            = &lm363x_regulator_voltage_table_ops,
-               .n_voltages     = LM36274_LDO_VSEL_MAX,
+               .n_voltages     = LM36274_LDO_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
@@ -254,7 +254,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
                .of_match       = "vneg",
                .id             = LM36274_LDO_NEG,
                .ops            = &lm363x_regulator_voltage_table_ops,
-               .n_voltages     = LM36274_LDO_VSEL_MAX,
+               .n_voltages     = LM36274_LDO_VSEL_MAX + 1,
                .min_uV         = LM36274_VOLTAGE_MIN,
                .uV_step        = LM363X_STEP_50mV,
                .type           = REGULATOR_VOLTAGE,
index 0c440c5..4ae12ac 100644 (file)
@@ -65,7 +65,6 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev,
                                       int ramp_delay)
 {
        int id = rdev_get_id(rdev);
-       struct lp87565 *lp87565 = rdev_get_drvdata(rdev);
        unsigned int reg;
        int ret;
 
@@ -86,11 +85,11 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev,
        else
                reg = 0;
 
-       ret = regmap_update_bits(lp87565->regmap, regulators[id].ctrl2_reg,
+       ret = regmap_update_bits(rdev->regmap, regulators[id].ctrl2_reg,
                                 LP87565_BUCK_CTRL_2_SLEW_RATE,
                                 reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE));
        if (ret) {
-               dev_err(lp87565->dev, "SLEW RATE write failed: %d\n", ret);
+               dev_err(&rdev->dev, "SLEW RATE write failed: %d\n", ret);
                return ret;
        }
 
index 1b00f36..00e9bb9 100644 (file)
@@ -464,7 +464,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
 {
        struct lp8788 *lp = ldo->lp;
        enum lp8788_ext_ldo_en_id enable_id;
-       u8 en_mask[] = {
+       static const u8 en_mask[] = {
                [EN_ALDO1]   = LP8788_EN_SEL_ALDO1_M,
                [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M,
                [EN_ALDO5]   = LP8788_EN_SEL_ALDO5_M,
index 8020eb5..c8e579e 100644 (file)
@@ -257,7 +257,7 @@ static int max77686_of_parse_cb(struct device_node *np,
        case MAX77686_BUCK9:
        case MAX77686_LDO20 ... MAX77686_LDO22:
                config->ena_gpiod = gpiod_get_from_of_node(np,
-                               "maxim,ena",
+                               "maxim,ena-gpios",
                                0,
                                GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
                                "max77686-regulator");
index 4bca544..347043a 100644 (file)
@@ -485,7 +485,6 @@ static int max8660_probe(struct i2c_client *client,
                rdev = devm_regulator_register(&client->dev,
                                                  &max8660_reg[id], &config);
                if (IS_ERR(rdev)) {
-                       ret = PTR_ERR(rdev);
                        dev_err(&client->dev, "failed to register %s\n",
                                max8660_reg[id].name);
                        return PTR_ERR(rdev);
diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c
new file mode 100644 (file)
index 0000000..ba42682
--- /dev/null
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2019 MediaTek Inc.
+
+#include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6358-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6358_BUCK_MODE_AUTO  0
+#define MT6358_BUCK_MODE_FORCE_PWM     1
+
+/*
+ * MT6358 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ */
+struct mt6358_regulator_info {
+       struct regulator_desc desc;
+       u32 status_reg;
+       u32 qi;
+       const u32 *index_table;
+       unsigned int n_table;
+       u32 vsel_shift;
+       u32 da_vsel_reg;
+       u32 da_vsel_mask;
+       u32 da_vsel_shift;
+       u32 modeset_reg;
+       u32 modeset_mask;
+       u32 modeset_shift;
+};
+
+#define MT6358_BUCK(match, vreg, min, max, step,               \
+       volt_ranges, vosel_mask, _da_vsel_reg, _da_vsel_mask,   \
+       _da_vsel_shift, _modeset_reg, _modeset_shift)           \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_range_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg,         \
+               .owner = THIS_MODULE,           \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .linear_ranges = volt_ranges,           \
+               .n_linear_ranges = ARRAY_SIZE(volt_ranges),     \
+               .vsel_reg = MT6358_BUCK_##vreg##_ELR0,  \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = MT6358_BUCK_##vreg##_CON0,        \
+               .enable_mask = BIT(0),  \
+               .of_map_mode = mt6358_map_mode, \
+       },      \
+       .status_reg = MT6358_BUCK_##vreg##_DBG1,        \
+       .qi = BIT(0),   \
+       .da_vsel_reg = _da_vsel_reg,    \
+       .da_vsel_mask = _da_vsel_mask,  \
+       .da_vsel_shift = _da_vsel_shift,        \
+       .modeset_reg = _modeset_reg,    \
+       .modeset_mask = BIT(_modeset_shift),    \
+       .modeset_shift = _modeset_shift \
+}
+
+#define MT6358_LDO(match, vreg, ldo_volt_table,        \
+       ldo_index_table, enreg, enbit, vosel,   \
+       vosel_mask, vosel_shift)        \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_table_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = ARRAY_SIZE(ldo_volt_table),       \
+               .volt_table = ldo_volt_table,   \
+               .vsel_reg = vosel,      \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = enreg,    \
+               .enable_mask = BIT(enbit),      \
+       },      \
+       .status_reg = MT6358_LDO_##vreg##_CON1, \
+       .qi = BIT(15),  \
+       .index_table = ldo_index_table, \
+       .n_table = ARRAY_SIZE(ldo_index_table), \
+       .vsel_shift = vosel_shift,      \
+}
+
+#define MT6358_LDO1(match, vreg, min, max, step,       \
+       volt_ranges, _da_vsel_reg, _da_vsel_mask,       \
+       _da_vsel_shift, vosel, vosel_mask)      \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_range_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .linear_ranges = volt_ranges,   \
+               .n_linear_ranges = ARRAY_SIZE(volt_ranges),     \
+               .vsel_reg = vosel,      \
+               .vsel_mask = vosel_mask,        \
+               .enable_reg = MT6358_LDO_##vreg##_CON0, \
+               .enable_mask = BIT(0),  \
+       },      \
+       .da_vsel_reg = _da_vsel_reg,    \
+       .da_vsel_mask = _da_vsel_mask,  \
+       .da_vsel_shift = _da_vsel_shift,        \
+       .status_reg = MT6358_LDO_##vreg##_DBG1, \
+       .qi = BIT(0),   \
+}
+
+#define MT6358_REG_FIXED(match, vreg,  \
+       enreg, enbit, volt)     \
+[MT6358_ID_##vreg] = { \
+       .desc = {       \
+               .name = #vreg,  \
+               .of_match = of_match_ptr(match),        \
+               .ops = &mt6358_volt_fixed_ops,  \
+               .type = REGULATOR_VOLTAGE,      \
+               .id = MT6358_ID_##vreg, \
+               .owner = THIS_MODULE,   \
+               .n_voltages = 1,        \
+               .enable_reg = enreg,    \
+               .enable_mask = BIT(enbit),      \
+               .min_uV = volt, \
+       },      \
+       .status_reg = MT6358_LDO_##vreg##_CON1, \
+       .qi = BIT(15),                                                  \
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+       REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const struct regulator_linear_range buck_volt_range4[] = {
+       REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500),
+};
+
+static const u32 vdram2_voltages[] = {
+       600000, 1800000,
+};
+
+static const u32 vsim_voltages[] = {
+       1700000, 1800000, 2700000, 3000000, 3100000,
+};
+
+static const u32 vibr_voltages[] = {
+       1200000, 1300000, 1500000, 1800000,
+       2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 vusb_voltages[] = {
+       3000000, 3100000,
+};
+
+static const u32 vcamd_voltages[] = {
+       900000, 1000000, 1100000, 1200000,
+       1300000, 1500000, 1800000,
+};
+
+static const u32 vefuse_voltages[] = {
+       1700000, 1800000, 1900000,
+};
+
+static const u32 vmch_vemc_voltages[] = {
+       2900000, 3000000, 3300000,
+};
+
+static const u32 vcama_voltages[] = {
+       1800000, 2500000, 2700000,
+       2800000, 2900000, 3000000,
+};
+
+static const u32 vcn33_bt_wifi_voltages[] = {
+       3300000, 3400000, 3500000,
+};
+
+static const u32 vmc_voltages[] = {
+       1800000, 2900000, 3000000, 3300000,
+};
+
+static const u32 vldo28_voltages[] = {
+       2800000, 3000000,
+};
+
+static const u32 vdram2_idx[] = {
+       0, 12,
+};
+
+static const u32 vsim_idx[] = {
+       3, 4, 8, 11, 12,
+};
+
+static const u32 vibr_idx[] = {
+       0, 1, 2, 4, 5, 9, 11, 13,
+};
+
+static const u32 vusb_idx[] = {
+       3, 4,
+};
+
+static const u32 vcamd_idx[] = {
+       3, 4, 5, 6, 7, 9, 12,
+};
+
+static const u32 vefuse_idx[] = {
+       11, 12, 13,
+};
+
+static const u32 vmch_vemc_idx[] = {
+       2, 3, 5,
+};
+
+static const u32 vcama_idx[] = {
+       0, 7, 9, 10, 11, 12,
+};
+
+static const u32 vcn33_bt_wifi_idx[] = {
+       1, 2, 3,
+};
+
+static const u32 vmc_idx[] = {
+       4, 10, 11, 13,
+};
+
+static const u32 vldo28_idx[] = {
+       1, 3,
+};
+
+static unsigned int mt6358_map_mode(unsigned int mode)
+{
+       return mode == MT6358_BUCK_MODE_AUTO ?
+               REGULATOR_MODE_NORMAL : REGULATOR_MODE_FAST;
+}
+
+static int mt6358_set_voltage_sel(struct regulator_dev *rdev,
+                                 unsigned int selector)
+{
+       int idx, ret;
+       const u32 *pvol;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       pvol = info->index_table;
+
+       idx = pvol[selector];
+       ret = regmap_update_bits(rdev->regmap, info->desc.vsel_reg,
+                                info->desc.vsel_mask,
+                                idx << info->vsel_shift);
+
+       return ret;
+}
+
+static int mt6358_get_voltage_sel(struct regulator_dev *rdev)
+{
+       int idx, ret;
+       u32 selector;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       const u32 *pvol;
+
+       ret = regmap_read(rdev->regmap, info->desc.vsel_reg, &selector);
+       if (ret != 0) {
+               dev_info(&rdev->dev,
+                        "Failed to get mt6358 %s vsel reg: %d\n",
+                        info->desc.name, ret);
+               return ret;
+       }
+
+       selector = (selector & info->desc.vsel_mask) >> info->vsel_shift;
+       pvol = info->index_table;
+       for (idx = 0; idx < info->desc.n_voltages; idx++) {
+               if (pvol[idx] == selector)
+                       return idx;
+       }
+
+       return -EINVAL;
+}
+
+static int mt6358_get_buck_voltage_sel(struct regulator_dev *rdev)
+{
+       int ret, regval;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->da_vsel_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to get mt6358 Buck %s vsel reg: %d\n",
+                       info->desc.name, ret);
+               return ret;
+       }
+
+       ret = (regval >> info->da_vsel_shift) & info->da_vsel_mask;
+
+       return ret;
+}
+
+static int mt6358_get_status(struct regulator_dev *rdev)
+{
+       int ret;
+       u32 regval;
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->status_reg, &regval);
+       if (ret != 0) {
+               dev_info(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+               return ret;
+       }
+
+       return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6358_regulator_set_mode(struct regulator_dev *rdev,
+                                    unsigned int mode)
+{
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       int val;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               val = MT6358_BUCK_MODE_FORCE_PWM;
+               break;
+       case REGULATOR_MODE_NORMAL:
+               val = MT6358_BUCK_MODE_AUTO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev_dbg(&rdev->dev, "mt6358 buck set_mode %#x, %#x, %#x, %#x\n",
+               info->modeset_reg, info->modeset_mask,
+               info->modeset_shift, val);
+
+       val <<= info->modeset_shift;
+
+       return regmap_update_bits(rdev->regmap, info->modeset_reg,
+                                 info->modeset_mask, val);
+}
+
+static unsigned int mt6358_regulator_get_mode(struct regulator_dev *rdev)
+{
+       struct mt6358_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret, regval;
+
+       ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to get mt6358 buck mode: %d\n", ret);
+               return ret;
+       }
+
+       switch ((regval & info->modeset_mask) >> info->modeset_shift) {
+       case MT6358_BUCK_MODE_AUTO:
+               return REGULATOR_MODE_NORMAL;
+       case MT6358_BUCK_MODE_FORCE_PWM:
+               return REGULATOR_MODE_FAST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct regulator_ops mt6358_volt_range_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = mt6358_get_buck_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+       .set_mode = mt6358_regulator_set_mode,
+       .get_mode = mt6358_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6358_volt_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .set_voltage_sel = mt6358_set_voltage_sel,
+       .get_voltage_sel = mt6358_get_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+};
+
+static const struct regulator_ops mt6358_volt_fixed_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6358_get_status,
+};
+
+/* The array is indexed by id(MT6358_ID_XXX) */
+static struct mt6358_regulator_info mt6358_regulators[] = {
+       MT6358_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500,
+                   buck_volt_range2, 0x7f, MT6358_BUCK_VDRAM1_DBG0, 0x7f,
+                   0, MT6358_VDRAM1_ANA_CON0, 8),
+       MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f,
+                   0, MT6358_VCORE_VGPU_ANA_CON0, 1),
+       MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+                   buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, 0,
+                   MT6358_VPA_ANA_CON0, 3),
+       MT6358_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VPROC11_DBG0, 0x7f,
+                   0, MT6358_VPROC_ANA_CON0, 1),
+       MT6358_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VPROC12_DBG0, 0x7f,
+                   0, MT6358_VPROC_ANA_CON0, 2),
+       MT6358_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, 0,
+                   MT6358_VCORE_VGPU_ANA_CON0, 2),
+       MT6358_BUCK("buck_vs2", VS2, 500000, 2087500, 12500,
+                   buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, 0,
+                   MT6358_VS2_ANA_CON0, 8),
+       MT6358_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250,
+                   buck_volt_range1, 0x7f, MT6358_BUCK_VMODEM_DBG0, 0x7f,
+                   0, MT6358_VMODEM_ANA_CON0, 8),
+       MT6358_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500,
+                   buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, 0,
+                   MT6358_VS1_ANA_CON0, 8),
+       MT6358_REG_FIXED("ldo_vrf12", VRF12,
+                        MT6358_LDO_VRF12_CON0, 0, 1200000),
+       MT6358_REG_FIXED("ldo_vio18", VIO18,
+                        MT6358_LDO_VIO18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vcamio", VCAMIO,
+                        MT6358_LDO_VCAMIO_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vcn18", VCN18, MT6358_LDO_VCN18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vfe28", VFE28, MT6358_LDO_VFE28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vcn28", VCN28, MT6358_LDO_VCN28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vxo22", VXO22, MT6358_LDO_VXO22_CON0, 0, 2200000),
+       MT6358_REG_FIXED("ldo_vaux18", VAUX18,
+                        MT6358_LDO_VAUX18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vbif28", VBIF28,
+                        MT6358_LDO_VBIF28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_vio28", VIO28, MT6358_LDO_VIO28_CON0, 0, 2800000),
+       MT6358_REG_FIXED("ldo_va12", VA12, MT6358_LDO_VA12_CON0, 0, 1200000),
+       MT6358_REG_FIXED("ldo_vrf18", VRF18, MT6358_LDO_VRF18_CON0, 0, 1800000),
+       MT6358_REG_FIXED("ldo_vaud28", VAUD28,
+                        MT6358_LDO_VAUD28_CON0, 0, 2800000),
+       MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx,
+                  MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0),
+       MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx,
+                  MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx,
+                  MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx,
+                  MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcamd", VCAMD, vcamd_voltages, vcamd_idx,
+                  MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx,
+                  MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vmch", VMCH, vmch_vemc_voltages, vmch_vemc_idx,
+                  MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcama1", VCAMA1, vcama_voltages, vcama_idx,
+                  MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vemc", VEMC, vmch_vemc_voltages, vmch_vemc_idx,
+                  MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700, 8),
+       MT6358_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_wifi_voltages,
+                  vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_0,
+                  0, MT6358_VCN33_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_bt_wifi_voltages,
+                  vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_1,
+                  0, MT6358_VCN33_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vcama2", VCAMA2, vcama_voltages, vcama_idx,
+                  MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx,
+                  MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00, 8),
+       MT6358_LDO("ldo_vldo28", VLDO28, vldo28_voltages, vldo28_idx,
+                  MT6358_LDO_VLDO28_CON0_0, 0,
+                  MT6358_VLDO28_ANA_CON0, 0x300, 8),
+       MT6358_LDO("ldo_vsim2", VSIM2, vsim_voltages, vsim_idx,
+                  MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00, 8),
+       MT6358_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON0, 0x7f),
+       MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON2, 0x7f),
+       MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON3, 0x7f),
+       MT6358_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250,
+                   buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f, 8,
+                   MT6358_LDO_VSRAM_CON1, 0x7f),
+};
+
+static int mt6358_regulator_probe(struct platform_device *pdev)
+{
+       struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = {};
+       struct regulator_dev *rdev;
+       int i;
+
+       for (i = 0; i < MT6358_MAX_REGULATOR; i++) {
+               config.dev = &pdev->dev;
+               config.driver_data = &mt6358_regulators[i];
+               config.regmap = mt6397->regmap;
+
+               rdev = devm_regulator_register(&pdev->dev,
+                                              &mt6358_regulators[i].desc,
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "failed to register %s\n",
+                               mt6358_regulators[i].desc.name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id mt6358_platform_ids[] = {
+       {"mt6358-regulator", 0},
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6358_platform_ids);
+
+static struct platform_driver mt6358_regulator_driver = {
+       .driver = {
+               .name = "mt6358-regulator",
+       },
+       .probe = mt6358_regulator_probe,
+       .id_table = mt6358_platform_ids,
+};
+
+module_platform_driver(mt6358_regulator_driver);
+
+MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6358 PMIC");
+MODULE_LICENSE("GPL");
index b2c2d01..db6c085 100644 (file)
@@ -50,6 +50,20 @@ enum rpmh_regulator_type {
 #define PMIC4_BOB_MODE_AUTO                    2
 #define PMIC4_BOB_MODE_PWM                     3
 
+#define PMIC5_LDO_MODE_RETENTION               3
+#define PMIC5_LDO_MODE_LPM                     4
+#define PMIC5_LDO_MODE_HPM                     7
+
+#define PMIC5_SMPS_MODE_RETENTION              3
+#define PMIC5_SMPS_MODE_PFM                    4
+#define PMIC5_SMPS_MODE_AUTO                   6
+#define PMIC5_SMPS_MODE_PWM                    7
+
+#define PMIC5_BOB_MODE_PASS                    2
+#define PMIC5_BOB_MODE_PFM                     4
+#define PMIC5_BOB_MODE_AUTO                    6
+#define PMIC5_BOB_MODE_PWM                     7
+
 /**
  * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
  * @regulator_type:            RPMh accelerator type used to manage this
@@ -488,6 +502,14 @@ static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = -EINVAL,
 };
 
+static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = PMIC5_LDO_MODE_RETENTION,
+       [REGULATOR_MODE_IDLE]    = PMIC5_LDO_MODE_LPM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_LDO_MODE_HPM,
+       [REGULATOR_MODE_FAST]    = -EINVAL,
+};
+
 static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
 {
        unsigned int mode;
@@ -518,6 +540,14 @@ static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = PMIC4_SMPS_MODE_PWM,
 };
 
+static const int pmic_mode_map_pmic5_smps[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = PMIC5_SMPS_MODE_RETENTION,
+       [REGULATOR_MODE_IDLE]    = PMIC5_SMPS_MODE_PFM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_SMPS_MODE_AUTO,
+       [REGULATOR_MODE_FAST]    = PMIC5_SMPS_MODE_PWM,
+};
+
 static unsigned int
 rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
 {
@@ -552,6 +582,14 @@ static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
        [REGULATOR_MODE_FAST]    = PMIC4_BOB_MODE_PWM,
 };
 
+static const int pmic_mode_map_pmic5_bob[REGULATOR_MODE_STANDBY + 1] = {
+       [REGULATOR_MODE_INVALID] = -EINVAL,
+       [REGULATOR_MODE_STANDBY] = -EINVAL,
+       [REGULATOR_MODE_IDLE]    = PMIC5_BOB_MODE_PFM,
+       [REGULATOR_MODE_NORMAL]  = PMIC5_BOB_MODE_AUTO,
+       [REGULATOR_MODE_FAST]    = PMIC5_BOB_MODE_PWM,
+};
+
 static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
 {
        unsigned int mode;
@@ -637,6 +675,72 @@ static const struct rpmh_vreg_hw_data pmic4_lvs = {
        /* LVS hardware does not support voltage or mode configuration. */
 };
 
+static const struct rpmh_vreg_hw_data pmic5_pldo = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+       .n_voltages = 256,
+       .hpm_min_load_uA = 10000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
+       .n_voltages = 63,
+       .hpm_min_load_uA = 10000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_nldo = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_drms_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000),
+       .n_voltages = 124,
+       .hpm_min_load_uA = 30000,
+       .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+       .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+       .n_voltages = 216,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
+       .n_voltages = 264,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(2800000, 0, 4, 1600),
+       .n_voltages = 5,
+       .pmic_mode_map = pmic_mode_map_pmic5_smps,
+       .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_bob = {
+       .regulator_type = VRM,
+       .ops = &rpmh_regulator_vrm_bypass_ops,
+       .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 135, 32000),
+       .n_voltages = 136,
+       .pmic_mode_map = pmic_mode_map_pmic5_bob,
+       .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
 #define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
 { \
        .name           = _name, \
@@ -705,6 +809,75 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
        {},
 };
 
+static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_ftsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_ftsmps510, "vdd-s2"),
+       RPMH_VREG("smps3",  "smp%s3",  &pmic5_ftsmps510, "vdd-s3"),
+       RPMH_VREG("smps4",  "smp%s4",  &pmic5_hfsmps510,   "vdd-s4"),
+       RPMH_VREG("smps5",  "smp%s5",  &pmic5_hfsmps510,   "vdd-s5"),
+       RPMH_VREG("smps6",  "smp%s6",  &pmic5_ftsmps510, "vdd-s6"),
+       RPMH_VREG("smps7",  "smp%s7",  &pmic5_ftsmps510, "vdd-s7"),
+       RPMH_VREG("smps8",  "smp%s8",  &pmic5_ftsmps510, "vdd-s8"),
+       RPMH_VREG("smps9",  "smp%s9",  &pmic5_ftsmps510, "vdd-s9"),
+       RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_pldo,      "vdd-l2-l10"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_nldo,      "vdd-l6-l9"),
+       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo,      "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_nldo,      "vdd-l6-l9"),
+       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_pldo,      "vdd-l2-l10"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_nldo,      "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo12",  "ldo%s12", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo13",  "ldo%s13", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo14",  "ldo%s14", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo15",  "ldo%s15", &pmic5_pldo_lv,   "vdd-l7-l12-l14-l15"),
+       RPMH_VREG("ldo16",  "ldo%s16", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,      "vdd-l13-l6-l17"),
+       RPMH_VREG("ldo18",  "ldo%s18", &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       {},
+};
+
+static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_ftsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_ftsmps510, "vdd-s2"),
+       RPMH_VREG("smps3",  "smp%s3",  &pmic5_ftsmps510, "vdd-s3"),
+       RPMH_VREG("smps4",  "smp%s4",  &pmic5_ftsmps510, "vdd-s4"),
+       RPMH_VREG("smps5",  "smp%s5",  &pmic5_ftsmps510, "vdd-s5"),
+       RPMH_VREG("smps6",  "smp%s6",  &pmic5_ftsmps510, "vdd-s6"),
+       RPMH_VREG("smps7",  "smp%s7",  &pmic5_ftsmps510, "vdd-s7"),
+       RPMH_VREG("smps8",  "smp%s8",  &pmic5_hfsmps510, "vdd-s8"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_pldo_lv,   "vdd-l1-l8"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo,      "vdd-l2-l3"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l2-l3"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo,      "vdd-l4-l5-l6"),
+       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo,      "vdd-l7-l11"),
+       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_pldo_lv,   "vdd-l1-l8-l11"),
+       RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_pldo,      "vdd-l9-l10"),
+       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_pldo,      "vdd-l9-l10"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_pldo,      "vdd-l7-l11"),
+       RPMH_VREG("bob",    "bob%s1",  &pmic5_bob,       "vdd-bob"),
+       {},
+};
+
+static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_hfsmps510, "vdd-s1"),
+       RPMH_VREG("smps2",  "smp%s2",  &pmic5_hfsmps515, "vdd-s2"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo,      "vdd-l1"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo,      "vdd-l2"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,      "vdd-l3"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo,      "vdd-l4"),
+       RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,      "vdd-l5-l6"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo,      "vdd-l5-l6"),
+       RPMH_VREG("ldo7",   "ldo%s6",  &pmic5_pldo_lv,   "vdd-l7"),
+       {},
+};
+
 static int rpmh_regulator_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -743,6 +916,22 @@ static int rpmh_regulator_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id rpmh_regulator_match_table[] = {
+       {
+               .compatible = "qcom,pm8005-rpmh-regulators",
+               .data = pm8005_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8009-rpmh-regulators",
+               .data = pm8009_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8150-rpmh-regulators",
+               .data = pm8150_vreg_data,
+       },
+       {
+               .compatible = "qcom,pm8150l-rpmh-regulators",
+               .data = pm8150l_vreg_data,
+       },
        {
                .compatible = "qcom,pm8998-rpmh-regulators",
                .data = pm8998_vreg_data,
@@ -751,10 +940,6 @@ static const struct of_device_id rpmh_regulator_match_table[] = {
                .compatible = "qcom,pmi8998-rpmh-regulators",
                .data = pmi8998_vreg_data,
        },
-       {
-               .compatible = "qcom,pm8005-rpmh-regulators",
-               .data = pm8005_vreg_data,
-       },
        {}
 };
 MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
index e7af0c5..61bd5ef 100644 (file)
@@ -606,7 +606,7 @@ static unsigned int rk8xx_regulator_of_map_mode(unsigned int mode)
        case 2:
                return REGULATOR_MODE_NORMAL;
        default:
-               return -EINVAL;
+               return REGULATOR_MODE_INVALID;
        }
 }
 
index 054baaa..5bc0088 100644 (file)
@@ -1226,7 +1226,7 @@ common_reg:
                        goto out;
                }
 
-               if (s2mps11->ext_control_gpiod[i]) {
+               if (config.ena_gpiod) {
                        ret = s2mps14_pmic_enable_ext_control(s2mps11,
                                        regulator);
                        if (ret < 0) {
index 04b7329..a0565da 100644 (file)
@@ -205,7 +205,7 @@ static int slg51000_of_parse_cb(struct device_node *np,
        ena_gpiod = devm_gpiod_get_from_of_node(chip->dev, np,
                                                "enable-gpios", 0,
                                                gflags, "gpio-en-ldo");
-       if (ena_gpiod) {
+       if (!IS_ERR(ena_gpiod)) {
                config->ena_gpiod = ena_gpiod;
                devm_gpiod_unhinge(chip->dev, config->ena_gpiod);
        }
@@ -447,18 +447,19 @@ static int slg51000_i2c_probe(struct i2c_client *client,
 {
        struct device *dev = &client->dev;
        struct slg51000 *chip;
-       struct gpio_desc *cs_gpiod = NULL;
+       struct gpio_desc *cs_gpiod;
        int error, ret;
 
        chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node,
-                                              "dlg,cs-gpios", 0,
-                                              GPIOD_OUT_HIGH
-                                              | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
-                                              "slg51000-cs");
+       cs_gpiod = devm_gpiod_get_optional(dev, "dlg,cs",
+                                          GPIOD_OUT_HIGH |
+                                               GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+       if (IS_ERR(cs_gpiod))
+               return PTR_ERR(cs_gpiod);
+
        if (cs_gpiod) {
                dev_info(dev, "Found chip selector property\n");
                chip->cs_gpiod = cs_gpiod;
index 2a89766..03f162f 100644 (file)
@@ -20,7 +20,6 @@
 #define STM32MP1_SYSCFG_EN_BOOSTER_MASK        BIT(8)
 
 static const struct regulator_ops stm32h7_booster_ops = {
-       .list_voltage   = regulator_list_voltage_linear,
        .enable         = regulator_enable_regmap,
        .disable        = regulator_disable_regmap,
        .is_enabled     = regulator_is_enabled_regmap,
@@ -31,7 +30,6 @@ static const struct regulator_desc stm32h7_booster_desc = {
        .supply_name = "vdda",
        .n_voltages = 1,
        .type = REGULATOR_VOLTAGE,
-       .min_uV = 3300000,
        .fixed_uV = 3300000,
        .ramp_delay = 66000, /* up to 50us to stabilize */
        .ops = &stm32h7_booster_ops,
@@ -53,7 +51,6 @@ static int stm32mp1_booster_disable(struct regulator_dev *rdev)
 }
 
 static const struct regulator_ops stm32mp1_booster_ops = {
-       .list_voltage   = regulator_list_voltage_linear,
        .enable         = stm32mp1_booster_enable,
        .disable        = stm32mp1_booster_disable,
        .is_enabled     = regulator_is_enabled_regmap,
@@ -64,7 +61,6 @@ static const struct regulator_desc stm32mp1_booster_desc = {
        .supply_name = "vdda",
        .n_voltages = 1,
        .type = REGULATOR_VOLTAGE,
-       .min_uV = 3300000,
        .fixed_uV = 3300000,
        .ramp_delay = 66000,
        .ops = &stm32mp1_booster_ops,
diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c
new file mode 100644 (file)
index 0000000..92adb4f
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// SY8824C/SY8824E regulator driver
+//
+// Copyright (C) 2019 Synaptics Incorporated
+//
+// Author: Jisheng Zhang <jszhang@kernel.org>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SY8824C_BUCK_EN                (1 << 7)
+#define SY8824C_MODE           (1 << 6)
+
+struct sy8824_config {
+       /* registers */
+       unsigned int vol_reg;
+       unsigned int mode_reg;
+       unsigned int enable_reg;
+       /* Voltage range and step(linear) */
+       unsigned int vsel_min;
+       unsigned int vsel_step;
+       unsigned int vsel_count;
+};
+
+struct sy8824_device_info {
+       struct device *dev;
+       struct regulator_desc desc;
+       struct regulator_init_data *regulator;
+       const struct sy8824_config *cfg;
+};
+
+static int sy8824_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct sy8824_device_info *di = rdev_get_drvdata(rdev);
+       const struct sy8824_config *cfg = di->cfg;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               regmap_update_bits(rdev->regmap, cfg->mode_reg,
+                                  SY8824C_MODE, SY8824C_MODE);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               regmap_update_bits(rdev->regmap, cfg->mode_reg,
+                                  SY8824C_MODE, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static unsigned int sy8824_get_mode(struct regulator_dev *rdev)
+{
+       struct sy8824_device_info *di = rdev_get_drvdata(rdev);
+       const struct sy8824_config *cfg = di->cfg;
+       u32 val;
+       int ret = 0;
+
+       ret = regmap_read(rdev->regmap, cfg->mode_reg, &val);
+       if (ret < 0)
+               return ret;
+       if (val & SY8824C_MODE)
+               return REGULATOR_MODE_FAST;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static const struct regulator_ops sy8824_regulator_ops = {
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .map_voltage = regulator_map_voltage_linear,
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_mode = sy8824_set_mode,
+       .get_mode = sy8824_get_mode,
+};
+
+static int sy8824_regulator_register(struct sy8824_device_info *di,
+                       struct regulator_config *config)
+{
+       struct regulator_desc *rdesc = &di->desc;
+       const struct sy8824_config *cfg = di->cfg;
+       struct regulator_dev *rdev;
+
+       rdesc->name = "sy8824-reg";
+       rdesc->supply_name = "vin";
+       rdesc->ops = &sy8824_regulator_ops;
+       rdesc->type = REGULATOR_VOLTAGE;
+       rdesc->n_voltages = cfg->vsel_count;
+       rdesc->enable_reg = cfg->enable_reg;
+       rdesc->enable_mask = SY8824C_BUCK_EN;
+       rdesc->min_uV = cfg->vsel_min;
+       rdesc->uV_step = cfg->vsel_step;
+       rdesc->vsel_reg = cfg->vol_reg;
+       rdesc->vsel_mask = cfg->vsel_count - 1;
+       rdesc->owner = THIS_MODULE;
+
+       rdev = devm_regulator_register(di->dev, &di->desc, config);
+       return PTR_ERR_OR_ZERO(rdev);
+}
+
+static const struct regmap_config sy8824_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int sy8824_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device_node *np = dev->of_node;
+       struct sy8824_device_info *di;
+       struct regulator_config config = { };
+       struct regmap *regmap;
+       int ret;
+
+       di = devm_kzalloc(dev, sizeof(struct sy8824_device_info), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
+       if (!di->regulator) {
+               dev_err(dev, "Platform data not found!\n");
+               return -EINVAL;
+       }
+
+       di->dev = dev;
+       di->cfg = of_device_get_match_data(dev);
+
+       regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to allocate regmap!\n");
+               return PTR_ERR(regmap);
+       }
+       i2c_set_clientdata(client, di);
+
+       config.dev = di->dev;
+       config.init_data = di->regulator;
+       config.regmap = regmap;
+       config.driver_data = di;
+       config.of_node = np;
+
+       ret = sy8824_regulator_register(di, &config);
+       if (ret < 0)
+               dev_err(dev, "Failed to register regulator!\n");
+       return ret;
+}
+
+static const struct sy8824_config sy8824c_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x00,
+       .enable_reg = 0x00,
+       .vsel_min = 762500,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct sy8824_config sy8824e_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x00,
+       .enable_reg = 0x00,
+       .vsel_min = 700000,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct sy8824_config sy20276_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x01,
+       .enable_reg = 0x01,
+       .vsel_min = 600000,
+       .vsel_step = 10000,
+       .vsel_count = 128,
+};
+
+static const struct sy8824_config sy20278_cfg = {
+       .vol_reg = 0x00,
+       .mode_reg = 0x01,
+       .enable_reg = 0x01,
+       .vsel_min = 762500,
+       .vsel_step = 12500,
+       .vsel_count = 64,
+};
+
+static const struct of_device_id sy8824_dt_ids[] = {
+       {
+               .compatible = "silergy,sy8824c",
+               .data = &sy8824c_cfg
+       },
+       {
+               .compatible = "silergy,sy8824e",
+               .data = &sy8824e_cfg
+       },
+       {
+               .compatible = "silergy,sy20276",
+               .data = &sy20276_cfg
+       },
+       {
+               .compatible = "silergy,sy20278",
+               .data = &sy20278_cfg
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sy8824_dt_ids);
+
+static const struct i2c_device_id sy8824_id[] = {
+       { "sy8824", },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, sy8824_id);
+
+static struct i2c_driver sy8824_regulator_driver = {
+       .driver = {
+               .name = "sy8824-regulator",
+               .of_match_table = of_match_ptr(sy8824_dt_ids),
+       },
+       .probe = sy8824_i2c_probe,
+       .id_table = sy8824_id,
+};
+module_i2c_driver(sy8824_regulator_driver);
+
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver");
+MODULE_LICENSE("GPL v2");
index 6e22f5e..e302bd0 100644 (file)
@@ -138,7 +138,7 @@ static int tps65132_of_parse_cb(struct device_node *np,
 
        rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev,
                                        "enable", 0, &np->fwnode, 0, "enable");
-       if (IS_ERR(rpdata->en_gpiod)) {
+       if (IS_ERR_OR_NULL(rpdata->en_gpiod)) {
                ret = PTR_ERR(rpdata->en_gpiod);
 
                /* Ignore the error other than probe defer */
@@ -150,7 +150,7 @@ static int tps65132_of_parse_cb(struct device_node *np,
        rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child(
                                        tps->dev, "active-discharge", 0,
                                        &np->fwnode, 0, "active-discharge");
-       if (IS_ERR(rpdata->act_dis_gpiod)) {
+       if (IS_ERR_OR_NULL(rpdata->act_dis_gpiod)) {
                ret = PTR_ERR(rpdata->act_dis_gpiod);
 
                /* Ignore the error other than probe defer */
index 6fa15b2..866b4dd 100644 (file)
@@ -359,6 +359,17 @@ static const u16 VINTANA2_VSEL_table[] = {
        2500, 2750,
 };
 
+/* 600mV to 1450mV in 12.5 mV steps */
+static const struct regulator_linear_range VDD1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 68, 12500)
+};
+
+/* 600mV to 1450mV in 12.5 mV steps, everything above = 1500mV */
+static const struct regulator_linear_range VDD2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(600000, 0, 68, 12500),
+       REGULATOR_LINEAR_RANGE(1500000, 69, 69, 12500)
+};
+
 static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
@@ -427,6 +438,8 @@ static int twl4030smps_get_voltage(struct regulator_dev *rdev)
 }
 
 static const struct regulator_ops twl4030smps_ops = {
+       .list_voltage   = regulator_list_voltage_linear_range,
+
        .set_voltage    = twl4030smps_set_voltage,
        .get_voltage    = twl4030smps_get_voltage,
 };
@@ -466,7 +479,8 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
                }, \
        }
 
-#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
+#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf, \
+               n_volt) \
 static const struct twlreg_info TWL4030_INFO_##label = { \
        .base = offset, \
        .id = num, \
@@ -479,6 +493,9 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
                .owner = THIS_MODULE, \
                .enable_time = turnon_delay, \
                .of_map_mode = twl4030reg_map_mode, \
+               .n_voltages = n_volt, \
+               .n_linear_ranges = ARRAY_SIZE(label ## _ranges), \
+               .linear_ranges = label ## _ranges, \
                }, \
        }
 
@@ -518,8 +535,8 @@ TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00);
 TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08);
 TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08);
 TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08);
-TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08);
-TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08);
+TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08, 68);
+TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08, 69);
 /* VUSBCP is managed *only* by the USB subchip */
 TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
 TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
index 5fe208b..b8100c3 100644 (file)
@@ -57,6 +57,9 @@ struct twlreg_info {
 #define VREG_BC_PROC           3
 #define VREG_BC_CLK_RST                4
 
+/* TWL6030 LDO register values for VREG_VOLTAGE */
+#define TWL6030_VREG_VOLTAGE_WR_S   BIT(7)
+
 /* TWL6030 LDO register values for CFG_STATE */
 #define TWL6030_CFG_STATE_OFF  0x00
 #define TWL6030_CFG_STATE_ON   0x01
@@ -68,9 +71,10 @@ struct twlreg_info {
 #define TWL6030_CFG_STATE_APP(v)       (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
                                                TWL6030_CFG_STATE_APP_SHIFT)
 
-/* Flags for SMPS Voltage reading */
+/* Flags for SMPS Voltage reading and LDO reading*/
 #define SMPS_OFFSET_EN         BIT(0)
 #define SMPS_EXTENDED_EN       BIT(1)
+#define TWL_6030_WARM_RESET    BIT(3)
 
 /* twl6032 SMPS EPROM values */
 #define TWL6030_SMPS_OFFSET            0xB0
@@ -250,6 +254,9 @@ twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
 
+       if (info->flags & TWL_6030_WARM_RESET)
+               selector |= TWL6030_VREG_VOLTAGE_WR_S;
+
        return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
                            selector);
 }
@@ -259,6 +266,9 @@ static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev)
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE);
 
+       if (info->flags & TWL_6030_WARM_RESET)
+               vsel &= ~TWL6030_VREG_VOLTAGE_WR_S;
+
        return vsel;
 }
 
@@ -665,14 +675,14 @@ static int twlreg_probe(struct platform_device *pdev)
        struct regulation_constraints   *c;
        struct regulator_dev            *rdev;
        struct regulator_config         config = { };
+       struct device_node              *np = pdev->dev.of_node;
 
        template = of_device_get_match_data(&pdev->dev);
        if (!template)
                return -ENODEV;
 
        id = template->desc.id;
-       initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
-                                               &template->desc);
+       initdata = of_get_regulator_init_data(&pdev->dev, np, &template->desc);
        if (!initdata)
                return -EINVAL;
 
@@ -710,10 +720,13 @@ static int twlreg_probe(struct platform_device *pdev)
                break;
        }
 
+       if (of_get_property(np, "ti,retain-on-reset", NULL))
+               info->flags |= TWL_6030_WARM_RESET;
+
        config.dev = &pdev->dev;
        config.init_data = initdata;
        config.driver_data = info;
-       config.of_node = pdev->dev.of_node;
+       config.of_node = np;
 
        rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
        if (IS_ERR(rdev)) {
index 9026d5a..2311924 100644 (file)
@@ -185,6 +185,10 @@ static const struct of_device_id uniphier_regulator_match[] = {
                .compatible = "socionext,uniphier-pro4-usb3-regulator",
                .data = &uniphier_pro4_usb3_data,
        },
+       {
+               .compatible = "socionext,uniphier-pro5-usb3-regulator",
+               .data = &uniphier_pro4_usb3_data,
+       },
        {
                .compatible = "socionext,uniphier-pxs2-usb3-regulator",
                .data = &uniphier_pxs2_usb3_data,
index c7ee07c..28db887 100644 (file)
@@ -629,6 +629,7 @@ struct qeth_seqno {
 struct qeth_reply {
        struct list_head list;
        struct completion received;
+       spinlock_t lock;
        int (*callback)(struct qeth_card *, struct qeth_reply *,
                unsigned long);
        u32 seqno;
index 4d0caee..6502b14 100644 (file)
@@ -544,6 +544,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
        if (reply) {
                refcount_set(&reply->refcnt, 1);
                init_completion(&reply->received);
+               spin_lock_init(&reply->lock);
        }
        return reply;
 }
@@ -799,6 +800,13 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
 
        if (!reply->callback) {
                rc = 0;
+               goto no_callback;
+       }
+
+       spin_lock_irqsave(&reply->lock, flags);
+       if (reply->rc) {
+               /* Bail out when the requestor has already left: */
+               rc = reply->rc;
        } else {
                if (cmd) {
                        reply->offset = (u16)((char *)cmd - (char *)iob->data);
@@ -807,7 +815,9 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
                        rc = reply->callback(card, reply, (unsigned long)iob);
                }
        }
+       spin_unlock_irqrestore(&reply->lock, flags);
 
+no_callback:
        if (rc <= 0)
                qeth_notify_reply(reply, rc);
        qeth_put_reply(reply);
@@ -1749,6 +1759,16 @@ static int qeth_send_control_data(struct qeth_card *card,
                rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
 
        qeth_dequeue_reply(card, reply);
+
+       if (reply_cb) {
+               /* Wait until the callback for a late reply has completed: */
+               spin_lock_irq(&reply->lock);
+               if (rc)
+                       /* Zap any callback that's still pending: */
+                       reply->rc = rc;
+               spin_unlock_irq(&reply->lock);
+       }
+
        if (!rc)
                rc = reply->rc;
        qeth_put_reply(reply);
@@ -4354,6 +4374,10 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
            get_user(req_len, &ureq->hdr.req_len))
                return -EFAULT;
 
+       /* Sanitize user input, to avoid overflows in iob size calculation: */
+       if (req_len > QETH_BUFSIZE)
+               return -EINVAL;
+
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, req_len);
        if (!iob)
                return -ENOMEM;
index abcad09..f47b4b2 100644 (file)
@@ -459,6 +459,7 @@ static void sas_discover_domain(struct work_struct *work)
                pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
                /* Fall through */
 #endif
+               /* Fall through - only for the #else condition above. */
        default:
                error = -ENXIO;
                pr_err("unhandled device %d\n", dev->dev_type);
index 2c3bb8a..bade2e0 100644 (file)
@@ -824,6 +824,7 @@ struct lpfc_hba {
        uint32_t cfg_cq_poll_threshold;
        uint32_t cfg_cq_max_proc_limit;
        uint32_t cfg_fcp_cpu_map;
+       uint32_t cfg_fcp_mq_threshold;
        uint32_t cfg_hdw_queue;
        uint32_t cfg_irq_chann;
        uint32_t cfg_suppress_rsp;
index ea62322..d655586 100644 (file)
@@ -5708,6 +5708,19 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
 LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
             "Embed NVME Command in WQE");
 
+/*
+ * lpfc_fcp_mq_threshold: Set the maximum number of Hardware Queues
+ * the driver will advertise it supports to the SCSI layer.
+ *
+ *      0    = Set nr_hw_queues by the number of CPUs or HW queues.
+ *      1,128 = Manually specify the maximum nr_hw_queue value to be set,
+ *
+ * Value range is [0,256]. Default value is 8.
+ */
+LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF,
+           LPFC_FCP_MQ_THRESHOLD_MIN, LPFC_FCP_MQ_THRESHOLD_MAX,
+           "Set the number of SCSI Queues advertised");
+
 /*
  * lpfc_hdw_queue: Set the number of Hardware Queues the driver
  * will advertise it supports to the NVME and  SCSI layers. This also
@@ -6030,6 +6043,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_cq_poll_threshold,
        &dev_attr_lpfc_cq_max_proc_limit,
        &dev_attr_lpfc_fcp_cpu_map,
+       &dev_attr_lpfc_fcp_mq_threshold,
        &dev_attr_lpfc_hdw_queue,
        &dev_attr_lpfc_irq_chann,
        &dev_attr_lpfc_suppress_rsp,
@@ -7112,6 +7126,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        /* Initialize first burst. Target vs Initiator are different. */
        lpfc_nvme_enable_fb_init(phba, lpfc_nvme_enable_fb);
        lpfc_nvmet_fb_size_init(phba, lpfc_nvmet_fb_size);
+       lpfc_fcp_mq_threshold_init(phba, lpfc_fcp_mq_threshold);
        lpfc_hdw_queue_init(phba, lpfc_hdw_queue);
        lpfc_irq_chann_init(phba, lpfc_irq_chann);
        lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr);
index faf43b1..1ac98be 100644 (file)
@@ -4309,10 +4309,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        shost->max_cmd_len = 16;
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
-               if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ)
-                       shost->nr_hw_queues = phba->cfg_hdw_queue;
-               else
-                       shost->nr_hw_queues = phba->sli4_hba.num_present_cpu;
+               if (!phba->cfg_fcp_mq_threshold ||
+                   phba->cfg_fcp_mq_threshold > phba->cfg_hdw_queue)
+                       phba->cfg_fcp_mq_threshold = phba->cfg_hdw_queue;
+
+               shost->nr_hw_queues = min_t(int, 2 * num_possible_nodes(),
+                                           phba->cfg_fcp_mq_threshold);
 
                shost->dma_boundary =
                        phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
@@ -10776,12 +10778,31 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
        /* This loop sets up all CPUs that are affinitized with a
         * irq vector assigned to the driver. All affinitized CPUs
         * will get a link to that vectors IRQ and EQ.
+        *
+        * NULL affinity mask handling:
+        * If irq count is greater than one, log an error message.
+        * If the null mask is received for the first irq, find the
+        * first present cpu, and assign the eq index to ensure at
+        * least one EQ is assigned.
         */
        for (idx = 0; idx <  phba->cfg_irq_chann; idx++) {
                /* Get a CPU mask for all CPUs affinitized to this vector */
                maskp = pci_irq_get_affinity(phba->pcidev, idx);
-               if (!maskp)
-                       continue;
+               if (!maskp) {
+                       if (phba->cfg_irq_chann > 1)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "3329 No affinity mask found "
+                                               "for vector %d (%d)\n",
+                                               idx, phba->cfg_irq_chann);
+                       if (!idx) {
+                               cpu = cpumask_first(cpu_present_mask);
+                               cpup = &phba->sli4_hba.cpu_map[cpu];
+                               cpup->eq = idx;
+                               cpup->irq = pci_irq_vector(phba->pcidev, idx);
+                               cpup->flag |= LPFC_CPU_FIRST_IRQ;
+                       }
+                       break;
+               }
 
                i = 0;
                /* Loop through all CPUs associated with vector idx */
index 3aeca38..a81ef02 100644 (file)
 #define LPFC_HBA_HDWQ_MAX      128
 #define LPFC_HBA_HDWQ_DEF      0
 
+/* FCP MQ queue count limiting */
+#define LPFC_FCP_MQ_THRESHOLD_MIN      0
+#define LPFC_FCP_MQ_THRESHOLD_MAX      256
+#define LPFC_FCP_MQ_THRESHOLD_DEF      8
+
 /* Common buffer size to accomidate SCSI and NVME IO buffers */
 #define LPFC_COMMON_IO_BUF_SZ  768
 
index e5760c4..832af42 100644 (file)
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-#include <asm/sn/io.h>
-#endif
-
 
 /*
  * Compile time Options:
 
 #define NVRAM_DELAY()                  udelay(500)     /* 2 microseconds */
 
-#if defined(__ia64__) && !defined(ia64_platform_is)
-#define ia64_platform_is(foo)          (!strcmp(x, platform_name))
-#endif
-
-
 #define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020)
 #define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \
                        ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240)
@@ -1427,15 +1418,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
        ha->flags.reset_active = 0;
        ha->flags.abort_isp_active = 0;
 
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-       if (ia64_platform_is("sn2")) {
-               printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
-                      "dual channel lockup workaround\n", ha->host_no);
-               ha->flags.use_pci_vchannel = 1;
-               driver_setup.no_nvram = 1;
-       }
-#endif
-
        /* TODO: implement support for the 1040 nvram format */
        if (IS_ISP1040(ha))
                driver_setup.no_nvram = 1;
@@ -2251,13 +2233,6 @@ qla1280_nvram_config(struct scsi_qla_host *ha)
        mb[1] = nv->firmware_feature.f.enable_fast_posting;
        mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1;
        mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5;
-#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2)
-       if (ia64_platform_is("sn2")) {
-               printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
-                      "workaround\n", ha->host_no);
-               mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */
-       }
-#endif
        status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
 
        /* Retry count and delay. */
@@ -2888,12 +2863,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                                break;
 
                        dma_handle = sg_dma_address(s);
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-                       if (ha->flags.use_pci_vchannel)
-                               sn_pci_set_vchan(ha->pdev,
-                                                (unsigned long *)&dma_handle,
-                                                SCSI_BUS_32(cmd));
-#endif
                        *dword_ptr++ =
                                cpu_to_le32(lower_32_bits(dma_handle));
                        *dword_ptr++ =
@@ -2950,12 +2919,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                                if (cnt == 5)
                                        break;
                                dma_handle = sg_dma_address(s);
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-                               if (ha->flags.use_pci_vchannel)
-                                       sn_pci_set_vchan(ha->pdev,
-                                                        (unsigned long *)&dma_handle,
-                                                        SCSI_BUS_32(cmd));
-#endif
                                *dword_ptr++ =
                                        cpu_to_le32(lower_32_bits(dma_handle));
                                *dword_ptr++ =
index b496206..a1a8aef 100644 (file)
@@ -1055,9 +1055,6 @@ struct scsi_qla_host {
                uint32_t reset_active:1;                /* 3 */
                uint32_t abort_isp_active:1;            /* 4 */
                uint32_t disable_risc_code_load:1;      /* 5 */
-#ifdef __ia64__
-               uint32_t use_pci_vchannel:1;
-#endif
        } flags;
 
        struct nvram nvram;
index 8d560c5..6b7b390 100644 (file)
@@ -2956,6 +2956,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
        dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
            vha->gnl.ldma);
 
+       vha->gnl.l = NULL;
+
        vfree(vha->scan.l);
 
        if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
index da83034..d4c3bae 100644 (file)
@@ -4575,20 +4575,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
                rval = 1;
        }
 
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-       /*
-        * The SN2 does not provide BIOS emulation which means you can't change
-        * potentially bogus BIOS settings. Force the use of default settings
-        * for link rate and frame size.  Hope that the rest of the settings
-        * are valid.
-        */
-       if (ia64_platform_is("sn2")) {
-               nv->frame_payload_size = 2048;
-               if (IS_QLA23XX(ha))
-                       nv->special_options[1] = BIT_7;
-       }
-#endif
-
        /* Reset Initialization control block */
        memset(icb, 0, ha->init_cb_size);
 
index 2e58cff..98e60a3 100644 (file)
@@ -3440,6 +3440,12 @@ skip_dpc:
        return 0;
 
 probe_failed:
+       if (base_vha->gnl.l) {
+               dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size,
+                               base_vha->gnl.l, base_vha->gnl.ldma);
+               base_vha->gnl.l = NULL;
+       }
+
        if (base_vha->timer_active)
                qla2x00_stop_timer(base_vha);
        base_vha->flags.online = 0;
@@ -3673,7 +3679,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
        if (!atomic_read(&pdev->enable_cnt)) {
                dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size,
                    base_vha->gnl.l, base_vha->gnl.ldma);
-
+               base_vha->gnl.l = NULL;
                scsi_host_put(base_vha->host);
                kfree(ha);
                pci_set_drvdata(pdev, NULL);
@@ -3713,6 +3719,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
        dma_free_coherent(&ha->pdev->dev,
                base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma);
 
+       base_vha->gnl.l = NULL;
+
        vfree(base_vha->scan.l);
 
        if (IS_QLAFX00(ha))
@@ -4816,6 +4824,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
                    "Alloc failed for scan database.\n");
                dma_free_coherent(&ha->pdev->dev, vha->gnl.size,
                    vha->gnl.l, vha->gnl.ldma);
+               vha->gnl.l = NULL;
                scsi_remove_host(vha->host);
                return NULL;
        }
index e274053..029da74 100644 (file)
@@ -7062,6 +7062,9 @@ static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
+       if (!vreg)
+               return 0;
+
        return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }
 
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
deleted file mode 100644 (file)
index a6c443d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Miscellaneous SN-specific devices
-#
-
-menu "SN Devices"
-       depends on SGI_SN
-
-config SGI_IOC3
-       tristate "SGI IOC3 Base IO support"
-       default m
-       ---help---
-       This option enables basic support for the SGI IOC3-based Base IO
-       controller card.  This option does not enable any specific
-       functions on such a card, but provides necessary infrastructure
-       for other drivers to utilize.
-
-       If you have an SGI Altix with an IOC3-based
-       I/O controller or a PCI IOC3 serial card say Y.
-       Otherwise say N.
-
-endmenu
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
deleted file mode 100644 (file)
index f0e809a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Altix device drivers.
-#
-#
-
-obj-$(CONFIG_SGI_IOC3) += ioc3.o
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
deleted file mode 100644 (file)
index 358025a..0000000
+++ /dev/null
@@ -1,844 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SGI IOC3 master driver and IRQ demuxer
- *
- * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
- * Heavily based on similar work by:
- *   Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
- *   Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/ioc3.h>
-#include <linux/rwsem.h>
-#include <linux/slab.h>
-
-#define IOC3_PCI_SIZE 0x100000
-
-static LIST_HEAD(ioc3_devices);
-static int ioc3_counter;
-static DECLARE_RWSEM(ioc3_devices_rwsem);
-
-static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
-static struct ioc3_submodule *ioc3_ethernet;
-static DEFINE_RWLOCK(ioc3_submodules_lock);
-
-/* NIC probing code */
-
-#define GPCR_MLAN_EN    0x00200000      /* enable MCR to pin 8 */
-
-static inline unsigned mcr_pack(unsigned pulse, unsigned sample)
-{
-       return (pulse << 10) | (sample << 2);
-}
-
-static int nic_wait(struct ioc3_driver_data *idd)
-{
-       unsigned mcr;
-
-        do {
-                mcr = readl(&idd->vma->mcr);
-        } while (!(mcr & 2));
-
-        return mcr & 1;
-}
-
-static int nic_reset(struct ioc3_driver_data *idd)
-{
-        int presence;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       writel(mcr_pack(500, 65), &idd->vma->mcr);
-       presence = nic_wait(idd);
-       local_irq_restore(flags);
-
-       udelay(500);
-
-        return presence;
-}
-
-static int nic_read_bit(struct ioc3_driver_data *idd)
-{
-       int result;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       writel(mcr_pack(6, 13), &idd->vma->mcr);
-       result = nic_wait(idd);
-       local_irq_restore(flags);
-
-       udelay(500);
-
-       return result;
-}
-
-static void nic_write_bit(struct ioc3_driver_data *idd, int bit)
-{
-       if (bit)
-               writel(mcr_pack(6, 110), &idd->vma->mcr);
-       else
-               writel(mcr_pack(80, 30), &idd->vma->mcr);
-
-       nic_wait(idd);
-}
-
-static unsigned nic_read_byte(struct ioc3_driver_data *idd)
-{
-       unsigned result = 0;
-       int i;
-
-       for (i = 0; i < 8; i++)
-               result = (result >> 1) | (nic_read_bit(idd) << 7);
-
-       return result;
-}
-
-static void nic_write_byte(struct ioc3_driver_data *idd, int byte)
-{
-       int i, bit;
-
-       for (i = 8; i; i--) {
-               bit = byte & 1;
-               byte >>= 1;
-
-               nic_write_bit(idd, bit);
-       }
-}
-
-static unsigned long
-nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr)
-{
-       int a, b, index, disc;
-
-       nic_reset(idd);
-
-       /* Search ROM.  */
-       nic_write_byte(idd, 0xF0);
-
-       /* Algorithm from ``Book of iButton Standards''.  */
-       for (index = 0, disc = 0; index < 64; index++) {
-               a = nic_read_bit(idd);
-               b = nic_read_bit(idd);
-
-               if (a && b) {
-                       printk(KERN_WARNING "IOC3 NIC search failed.\n");
-                       *last = 0;
-                       return 0;
-               }
-
-               if (!a && !b) {
-                       if (index == *last) {
-                               addr |= 1UL << index;
-                       } else if (index > *last) {
-                               addr &= ~(1UL << index);
-                               disc = index;
-                       } else if ((addr & (1UL << index)) == 0)
-                               disc = index;
-                       nic_write_bit(idd, (addr>>index)&1);
-                       continue;
-               } else {
-                       if (a)
-                               addr |= 1UL << index;
-                       else
-                               addr &= ~(1UL << index);
-                       nic_write_bit(idd, a);
-                       continue;
-               }
-       }
-       *last = disc;
-       return addr;
-}
-
-static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr)
-{
-       int index;
-
-       nic_reset(idd);
-       nic_write_byte(idd, 0xF0);
-       for (index = 0; index < 64; index++) {
-               nic_read_bit(idd);
-               nic_read_bit(idd);
-               nic_write_bit(idd, (addr>>index)&1);
-       }
-}
-
-static void crc16_byte(unsigned int *crc, unsigned char db)
-{
-       int i;
-
-       for(i=0;i<8;i++) {
-               *crc <<= 1;
-               if((db^(*crc>>16)) & 1)
-                       *crc ^= 0x8005;
-               db >>= 1;
-       }
-       *crc &= 0xFFFF;
-}
-
-static unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc)
-{
-       while(size--)
-               crc16_byte(&crc, *(dbs++));
-       return crc;
-}
-
-static void crc8_byte(unsigned int *crc, unsigned char db)
-{
-       int i,f;
-
-       for(i=0;i<8;i++) {
-               f = (*crc ^ db) & 1;
-               *crc >>= 1;
-               db >>= 1;
-               if(f)
-                       *crc ^= 0x8c;
-       }
-       *crc &= 0xff;
-}
-
-static unsigned int crc8_addr(unsigned long addr)
-{
-       int i;
-       unsigned int crc = 0x00;
-
-       for(i=0;i<8;i++)
-               crc8_byte(&crc, addr>>(i<<3));
-       return crc;
-}
-
-static void
-read_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page,
-                       unsigned char *redir, unsigned char *data)
-{
-       int loops = 16, i;
-
-       while(redir[page] != 0xFF) {
-               page = redir[page]^0xFF;
-               loops--;
-               if(loops<0) {
-                       printk(KERN_ERR "IOC3: NIC circular redirection\n");
-                       return;
-               }
-       }
-       loops = 3;
-       while(loops>0) {
-               nic_addr(idd, addr);
-               nic_write_byte(idd, 0xF0);
-               nic_write_byte(idd, (page << 5) & 0xE0);
-               nic_write_byte(idd, (page >> 3) & 0x1F);
-               for(i=0;i<0x20;i++)
-                       data[i] = nic_read_byte(idd);
-               if(crc16_area(data, 0x20, 0x0000) == 0x800d)
-                       return;
-               loops--;
-       }
-       printk(KERN_ERR "IOC3: CRC error in data page\n");
-       for(i=0;i<0x20;i++)
-               data[i] = 0x00;
-}
-
-static void
-read_redir_map(struct ioc3_driver_data *idd, unsigned long addr,
-                                        unsigned char *redir)
-{
-       int i,j,loops = 3,crc_ok;
-       unsigned int crc;
-
-       while(loops>0) {
-               crc_ok = 1;
-               nic_addr(idd, addr);
-               nic_write_byte(idd, 0xAA);
-               nic_write_byte(idd, 0x00);
-               nic_write_byte(idd, 0x01);
-               for(i=0;i<64;i+=8) {
-                       for(j=0;j<8;j++)
-                               redir[i+j] = nic_read_byte(idd);
-                       crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000);
-                       crc16_byte(&crc, nic_read_byte(idd));
-                       crc16_byte(&crc, nic_read_byte(idd));
-                       if(crc != 0x800d)
-                               crc_ok = 0;
-               }
-               if(crc_ok)
-                       return;
-               loops--;
-       }
-       printk(KERN_ERR "IOC3: CRC error in redirection page\n");
-       for(i=0;i<64;i++)
-               redir[i] = 0xFF;
-}
-
-static void read_nic(struct ioc3_driver_data *idd, unsigned long addr)
-{
-       unsigned char redir[64];
-       unsigned char data[64],part[32];
-       int i,j;
-
-       /* read redirections */
-       read_redir_map(idd, addr, redir);
-       /* read data pages */
-       read_redir_page(idd, addr, 0, redir, data);
-       read_redir_page(idd, addr, 1, redir, data+32);
-       /* assemble the part # */
-       j=0;
-       for(i=0;i<19;i++)
-               if(data[i+11] != ' ')
-                       part[j++] = data[i+11];
-       for(i=0;i<6;i++)
-               if(data[i+32] != ' ')
-                       part[j++] = data[i+32];
-       part[j] = 0;
-       /* skip Octane power supplies */
-       if(!strncmp(part, "060-0035-", 9))
-               return;
-       if(!strncmp(part, "060-0038-", 9))
-               return;
-       strcpy(idd->nic_part, part);
-       /* assemble the serial # */
-       j=0;
-       for(i=0;i<10;i++)
-               if(data[i+1] != ' ')
-                       idd->nic_serial[j++] = data[i+1];
-       idd->nic_serial[j] = 0;
-}
-
-static void read_mac(struct ioc3_driver_data *idd, unsigned long addr)
-{
-       int i, loops = 3;
-       unsigned char data[13];
-
-       while(loops>0) {
-               nic_addr(idd, addr);
-               nic_write_byte(idd, 0xF0);
-               nic_write_byte(idd, 0x00);
-               nic_write_byte(idd, 0x00);
-               nic_read_byte(idd);
-               for(i=0;i<13;i++)
-                       data[i] = nic_read_byte(idd);
-               if(crc16_area(data, 13, 0x0000) == 0x800d) {
-                       for(i=10;i>4;i--)
-                               idd->nic_mac[10-i] = data[i];
-                       return;
-               }
-               loops--;
-       }
-       printk(KERN_ERR "IOC3: CRC error in MAC address\n");
-       for(i=0;i<6;i++)
-               idd->nic_mac[i] = 0x00;
-}
-
-static void probe_nic(struct ioc3_driver_data *idd)
-{
-        int save = 0, loops = 3;
-        unsigned long first, addr;
-
-        writel(GPCR_MLAN_EN, &idd->vma->gpcr_s);
-
-        while(loops>0) {
-                idd->nic_part[0] = 0;
-                idd->nic_serial[0] = 0;
-                addr = first = nic_find(idd, &save, 0);
-                if(!first)
-                        return;
-                while(1) {
-                        if(crc8_addr(addr))
-                                break;
-                        else {
-                                switch(addr & 0xFF) {
-                                case 0x0B:
-                                        read_nic(idd, addr);
-                                        break;
-                                case 0x09:
-                                case 0x89:
-                                case 0x91:
-                                        read_mac(idd, addr);
-                                        break;
-                                }
-                        }
-                        addr = nic_find(idd, &save, addr);
-                        if(addr == first)
-                                return;
-                }
-                loops--;
-        }
-        printk(KERN_ERR "IOC3: CRC error in NIC address\n");
-}
-
-/* Interrupts */
-
-static void write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&idd->ir_lock, flags);
-       switch (which) {
-       case IOC3_W_IES:
-               writel(val, &idd->vma->sio_ies);
-               break;
-       case IOC3_W_IEC:
-               writel(val, &idd->vma->sio_iec);
-               break;
-       }
-       spin_unlock_irqrestore(&idd->ir_lock, flags);
-}
-static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd)
-{
-       unsigned long flag;
-       uint32_t intrs = 0;
-
-       spin_lock_irqsave(&idd->ir_lock, flag);
-       intrs = readl(&idd->vma->sio_ir);
-       intrs &= readl(&idd->vma->sio_ies);
-       spin_unlock_irqrestore(&idd->ir_lock, flag);
-       return intrs;
-}
-
-static irqreturn_t ioc3_intr_io(int irq, void *arg)
-{
-       unsigned long flags;
-       struct ioc3_driver_data *idd = arg;
-       int handled = 1, id;
-       unsigned int pending;
-
-       read_lock_irqsave(&ioc3_submodules_lock, flags);
-
-       if(idd->dual_irq && readb(&idd->vma->eisr)) {
-               /* send Ethernet IRQ to the driver */
-               if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
-                                               ioc3_ethernet->intr) {
-                       handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
-                                                       idd, 0);
-               }
-       }
-       pending = get_pending_intrs(idd);       /* look at the IO IRQs */
-
-       for(id=0;id<IOC3_MAX_SUBMODULES;id++) {
-               if(idd->active[id] && ioc3_submodules[id]
-                               && (pending & ioc3_submodules[id]->irq_mask)
-                               && ioc3_submodules[id]->intr) {
-                       write_ireg(idd, ioc3_submodules[id]->irq_mask,
-                                                       IOC3_W_IEC);
-                       if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
-                                  idd, pending & ioc3_submodules[id]->irq_mask))
-                               pending &= ~ioc3_submodules[id]->irq_mask;
-                       if (ioc3_submodules[id]->reset_mask)
-                               write_ireg(idd, ioc3_submodules[id]->irq_mask,
-                                                       IOC3_W_IES);
-               }
-       }
-       read_unlock_irqrestore(&ioc3_submodules_lock, flags);
-       if(pending) {
-               printk(KERN_WARNING
-                 "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending);
-               write_ireg(idd, pending, IOC3_W_IEC);
-               handled = 1;
-       }
-       return handled?IRQ_HANDLED:IRQ_NONE;
-}
-
-static irqreturn_t ioc3_intr_eth(int irq, void *arg)
-{
-       unsigned long flags;
-       struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
-       int handled = 1;
-
-       if(!idd->dual_irq)
-               return IRQ_NONE;
-       read_lock_irqsave(&ioc3_submodules_lock, flags);
-       if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
-                               && ioc3_ethernet->intr)
-               handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0);
-       read_unlock_irqrestore(&ioc3_submodules_lock, flags);
-       return handled?IRQ_HANDLED:IRQ_NONE;
-}
-
-void ioc3_enable(struct ioc3_submodule *is,
-                               struct ioc3_driver_data *idd, unsigned int irqs)
-{
-       write_ireg(idd, irqs & is->irq_mask, IOC3_W_IES);
-}
-
-void ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd,
-                               unsigned int irqs)
-{
-       writel(irqs & is->irq_mask, &idd->vma->sio_ir);
-}
-
-void ioc3_disable(struct ioc3_submodule *is,
-                               struct ioc3_driver_data *idd, unsigned int irqs)
-{
-       write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC);
-}
-
-void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&idd->gpio_lock, flags);
-       writel(val, &idd->vma->gpcr_s);
-       spin_unlock_irqrestore(&idd->gpio_lock, flags);
-}
-
-/* Keep it simple, stupid! */
-static int find_slot(void **tab, int max)
-{
-       int i;
-       for(i=0;i<max;i++)
-               if(!(tab[i]))
-                       return i;
-       return -1;
-}
-
-/* Register an IOC3 submodule */
-int ioc3_register_submodule(struct ioc3_submodule *is)
-{
-       struct ioc3_driver_data *idd;
-       int alloc_id;
-       unsigned long flags;
-
-       write_lock_irqsave(&ioc3_submodules_lock, flags);
-       alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES);
-       if(alloc_id != -1) {
-               ioc3_submodules[alloc_id] = is;
-               if(is->ethernet) {
-                       if(ioc3_ethernet==NULL)
-                               ioc3_ethernet=is;
-                       else
-                               printk(KERN_WARNING
-                                 "IOC3 Ethernet module already registered!\n");
-               }
-       }
-       write_unlock_irqrestore(&ioc3_submodules_lock, flags);
-
-       if(alloc_id == -1) {
-               printk(KERN_WARNING "Increase IOC3_MAX_SUBMODULES!\n");
-               return -ENOMEM;
-       }
-
-       is->id=alloc_id;
-
-       /* Initialize submodule for each IOC3 */
-       if (!is->probe)
-               return 0;
-
-       down_read(&ioc3_devices_rwsem);
-       list_for_each_entry(idd, &ioc3_devices, list) {
-               /* set to 1 for IRQs in probe */
-               idd->active[alloc_id] = 1;
-               idd->active[alloc_id] = !is->probe(is, idd);
-       }
-       up_read(&ioc3_devices_rwsem);
-
-       return 0;
-}
-
-/* Unregister an IOC3 submodule */
-void ioc3_unregister_submodule(struct ioc3_submodule *is)
-{
-       struct ioc3_driver_data *idd;
-       unsigned long flags;
-
-       write_lock_irqsave(&ioc3_submodules_lock, flags);
-       if(ioc3_submodules[is->id]==is)
-               ioc3_submodules[is->id]=NULL;
-       else
-               printk(KERN_WARNING
-                       "IOC3 submodule %s has wrong ID.\n",is->name);
-       if(ioc3_ethernet==is)
-               ioc3_ethernet = NULL;
-       write_unlock_irqrestore(&ioc3_submodules_lock, flags);
-
-       /* Remove submodule for each IOC3 */
-       down_read(&ioc3_devices_rwsem);
-       list_for_each_entry(idd, &ioc3_devices, list)
-               if(idd->active[is->id]) {
-                       if(is->remove)
-                               if(is->remove(is, idd))
-                                       printk(KERN_WARNING
-                                              "%s: IOC3 submodule %s remove failed "
-                                              "for pci_dev %s.\n",
-                                              __func__, module_name(is->owner),
-                                              pci_name(idd->pdev));
-                       idd->active[is->id] = 0;
-                       if(is->irq_mask)
-                               write_ireg(idd, is->irq_mask, IOC3_W_IEC);
-               }
-       up_read(&ioc3_devices_rwsem);
-}
-
-/*********************
- * Device management *
- *********************/
-
-static char *ioc3_class_names[] = { "unknown", "IP27 BaseIO", "IP30 system",
-                       "MENET 1/2/3", "MENET 4", "CADduo", "Altix Serial" };
-
-static int ioc3_class(struct ioc3_driver_data *idd)
-{
-       int res = IOC3_CLASS_NONE;
-       /* NIC-based logic */
-       if(!strncmp(idd->nic_part, "030-0891-", 9))
-               res = IOC3_CLASS_BASE_IP30;
-       if(!strncmp(idd->nic_part, "030-1155-", 9))
-               res = IOC3_CLASS_CADDUO;
-       if(!strncmp(idd->nic_part, "030-1657-", 9))
-               res = IOC3_CLASS_SERIAL;
-       if(!strncmp(idd->nic_part, "030-1664-", 9))
-               res = IOC3_CLASS_SERIAL;
-       /* total random heuristics */
-#ifdef CONFIG_SGI_IP27
-       if(!idd->nic_part[0])
-               res = IOC3_CLASS_BASE_IP27;
-#endif
-       /* print educational message */
-       printk(KERN_INFO "IOC3 part: [%s], serial: [%s] => class %s\n",
-                       idd->nic_part, idd->nic_serial, ioc3_class_names[res]);
-       return res;
-}
-/* Adds a new instance of an IOC3 card */
-static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
-       struct ioc3_driver_data *idd;
-       uint32_t pcmd;
-       int ret, id;
-
-       /* Enable IOC3 and take ownership of it */
-       if ((ret = pci_enable_device(pdev))) {
-               printk(KERN_WARNING
-                      "%s: Failed to enable IOC3 device for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               goto out;
-       }
-       pci_set_master(pdev);
-
-#ifdef USE_64BIT_DMA
-        ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-        if (!ret) {
-                ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-                if (ret < 0) {
-                        printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA "
-                               "for consistent allocations\n",
-                               __func__);
-                }
-       }
-#endif
-
-       /* Set up per-IOC3 data */
-       idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
-       if (!idd) {
-               printk(KERN_WARNING
-                      "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               ret = -ENODEV;
-               goto out_idd;
-       }
-       spin_lock_init(&idd->ir_lock);
-       spin_lock_init(&idd->gpio_lock);
-       idd->pdev = pdev;
-
-       /* Map all IOC3 registers.  These are shared between subdevices
-        * so the main IOC3 module manages them.
-        */
-       idd->pma = pci_resource_start(pdev, 0);
-       if (!idd->pma) {
-               printk(KERN_WARNING
-                      "%s: Unable to find IOC3 resource "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               ret = -ENODEV;
-               goto out_pci;
-       }
-       if (!request_mem_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
-               printk(KERN_WARNING
-                      "%s: Unable to request IOC3 region "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               ret = -ENODEV;
-               goto out_pci;
-       }
-       idd->vma = ioremap(idd->pma, IOC3_PCI_SIZE);
-       if (!idd->vma) {
-               printk(KERN_WARNING
-                      "%s: Unable to remap IOC3 region "
-                      "for pci_dev %s.\n",
-                      __func__, pci_name(pdev));
-               ret = -ENODEV;
-               goto out_misc_region;
-       }
-
-       /* Track PCI-device specific data */
-       pci_set_drvdata(pdev, idd);
-       down_write(&ioc3_devices_rwsem);
-       list_add_tail(&idd->list, &ioc3_devices);
-       idd->id = ioc3_counter++;
-       up_write(&ioc3_devices_rwsem);
-
-       idd->gpdr_shadow = readl(&idd->vma->gpdr);
-
-       /* Read IOC3 NIC contents */
-       probe_nic(idd);
-
-       /* Detect IOC3 class */
-       idd->class = ioc3_class(idd);
-
-       /* Initialize IOC3 */
-       pci_read_config_dword(pdev, PCI_COMMAND, &pcmd);
-       pci_write_config_dword(pdev, PCI_COMMAND,
-                               pcmd | PCI_COMMAND_MEMORY |
-                               PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
-                               PCI_SCR_DROP_MODE_EN);
-
-       write_ireg(idd, ~0, IOC3_W_IEC);
-       writel(~0, &idd->vma->sio_ir);
-
-       /* Set up IRQs */
-       if(idd->class == IOC3_CLASS_BASE_IP30
-                               || idd->class == IOC3_CLASS_BASE_IP27) {
-               writel(0, &idd->vma->eier);
-               writel(~0, &idd->vma->eisr);
-
-               idd->dual_irq = 1;
-               if (!request_irq(pdev->irq, ioc3_intr_eth, IRQF_SHARED,
-                                "ioc3-eth", (void *)idd)) {
-                       idd->irq_eth = pdev->irq;
-               } else {
-                       printk(KERN_WARNING
-                              "%s : request_irq fails for IRQ 0x%x\n ",
-                              __func__, pdev->irq);
-               }
-               if (!request_irq(pdev->irq+2, ioc3_intr_io, IRQF_SHARED,
-                                "ioc3-io", (void *)idd)) {
-                       idd->irq_io = pdev->irq+2;
-               } else {
-                       printk(KERN_WARNING
-                              "%s : request_irq fails for IRQ 0x%x\n ",
-                              __func__, pdev->irq+2);
-               }
-       } else {
-               if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED,
-                                "ioc3", (void *)idd)) {
-                       idd->irq_io = pdev->irq;
-               } else {
-                       printk(KERN_WARNING
-                              "%s : request_irq fails for IRQ 0x%x\n ",
-                              __func__, pdev->irq);
-               }
-       }
-
-       /* Add this IOC3 to all submodules */
-       for(id=0;id<IOC3_MAX_SUBMODULES;id++)
-               if(ioc3_submodules[id] && ioc3_submodules[id]->probe) {
-                       idd->active[id] = 1;
-                       idd->active[id] = !ioc3_submodules[id]->probe
-                                               (ioc3_submodules[id], idd);
-               }
-
-       printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev));
-
-       return 0;
-
-out_misc_region:
-       release_mem_region(idd->pma, IOC3_PCI_SIZE);
-out_pci:
-       kfree(idd);
-out_idd:
-       pci_disable_device(pdev);
-out:
-       return ret;
-}
-
-/* Removes a particular instance of an IOC3 card. */
-static void ioc3_remove(struct pci_dev *pdev)
-{
-       int id;
-       struct ioc3_driver_data *idd;
-
-       idd = pci_get_drvdata(pdev);
-
-       /* Remove this IOC3 from all submodules */
-       for(id=0;id<IOC3_MAX_SUBMODULES;id++)
-               if(idd->active[id]) {
-                       if(ioc3_submodules[id] && ioc3_submodules[id]->remove)
-                               if(ioc3_submodules[id]->remove(ioc3_submodules[id],
-                                                               idd))
-                                       printk(KERN_WARNING
-                                              "%s: IOC3 submodule 0x%s remove failed "
-                                              "for pci_dev %s.\n",
-                                               __func__,
-                                               module_name(ioc3_submodules[id]->owner),
-                                               pci_name(pdev));
-                       idd->active[id] = 0;
-               }
-
-       /* Clear and disable all IRQs */
-       write_ireg(idd, ~0, IOC3_W_IEC);
-       writel(~0, &idd->vma->sio_ir);
-
-       /* Release resources */
-       free_irq(idd->irq_io, (void *)idd);
-       if(idd->dual_irq)
-               free_irq(idd->irq_eth, (void *)idd);
-       iounmap(idd->vma);
-       release_mem_region(idd->pma, IOC3_PCI_SIZE);
-
-       /* Disable IOC3 and relinquish */
-       pci_disable_device(pdev);
-
-       /* Remove and free driver data */
-       down_write(&ioc3_devices_rwsem);
-       list_del(&idd->list);
-       up_write(&ioc3_devices_rwsem);
-       kfree(idd);
-}
-
-static struct pci_device_id ioc3_id_table[] = {
-       {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID},
-       {0}
-};
-
-static struct pci_driver ioc3_driver = {
-       .name = "IOC3",
-       .id_table = ioc3_id_table,
-       .probe = ioc3_probe,
-       .remove = ioc3_remove,
-};
-
-MODULE_DEVICE_TABLE(pci, ioc3_id_table);
-
-/*********************
- * Module management *
- *********************/
-
-/* Module load */
-static int __init ioc3_init(void)
-{
-       if (ia64_platform_is("sn2"))
-               return pci_register_driver(&ioc3_driver);
-       return -ENODEV;
-}
-
-/* Module unload */
-static void __exit ioc3_exit(void)
-{
-       pci_unregister_driver(&ioc3_driver);
-}
-
-module_init(ioc3_init);
-module_exit(ioc3_exit);
-
-MODULE_AUTHOR("Stanislaw Skowronek <skylark@linux-mips.org>");
-MODULE_DESCRIPTION("PCI driver for SGI IOC3");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(ioc3_register_submodule);
-EXPORT_SYMBOL_GPL(ioc3_unregister_submodule);
-EXPORT_SYMBOL_GPL(ioc3_ack);
-EXPORT_SYMBOL_GPL(ioc3_gpcr_set);
-EXPORT_SYMBOL_GPL(ioc3_disable);
-EXPORT_SYMBOL_GPL(ioc3_enable);
index de2e62c..e3eb19b 100644 (file)
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
+if ARCH_IXP4XX || COMPILE_TEST
+
 menu "IXP4xx SoC drivers"
 
 config IXP4XX_QMGR
@@ -15,3 +17,5 @@ config IXP4XX_NPE
          and is automatically selected by Ethernet and HSS drivers.
 
 endmenu
+
+endif
index d5cf953..7d622ea 100644 (file)
@@ -630,6 +630,9 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
        struct geni_wrapper *wrapper = se->wrapper;
        u32 val;
 
+       if (!wrapper)
+               return -EINVAL;
+
        *iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE);
        if (dma_mapping_error(wrapper->dev, *iova))
                return -EIO;
@@ -663,6 +666,9 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
        struct geni_wrapper *wrapper = se->wrapper;
        u32 val;
 
+       if (!wrapper)
+               return -EINVAL;
+
        *iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE);
        if (dma_mapping_error(wrapper->dev, *iova))
                return -EIO;
index bb77c22..ccc6d53 100644 (file)
@@ -141,7 +141,7 @@ static int __init am43xx_map_gic(void)
 }
 
 #ifdef CONFIG_SUSPEND
-struct wkup_m3_wakeup_src rtc_wake_src(void)
+static struct wkup_m3_wakeup_src rtc_wake_src(void)
 {
        u32 i;
 
@@ -157,7 +157,7 @@ struct wkup_m3_wakeup_src rtc_wake_src(void)
        return rtc_ext_wakeup;
 }
 
-int am33xx_rtc_only_idle(unsigned long wfi_flags)
+static int am33xx_rtc_only_idle(unsigned long wfi_flags)
 {
        omap_rtc_power_off_program(&omap_rtc->dev);
        am33xx_do_wfi_sram(wfi_flags);
@@ -252,7 +252,7 @@ static int am33xx_pm_begin(suspend_state_t state)
        if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) {
                nvmem = devm_nvmem_device_get(&omap_rtc->dev,
                                              "omap_rtc_scratch0");
-               if (nvmem)
+               if (!IS_ERR(nvmem))
                        nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
                                           (void *)&rtc_magic_val);
                rtc_only_idle = 1;
@@ -278,9 +278,12 @@ static void am33xx_pm_end(void)
        struct nvmem_device *nvmem;
 
        nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0");
+       if (IS_ERR(nvmem))
+               return;
+
        m3_ipc->ops->finish_low_power(m3_ipc);
        if (rtc_only_idle) {
-               if (retrigger_irq)
+               if (retrigger_irq) {
                        /*
                         * 32 bits of Interrupt Set-Pending correspond to 32
                         * 32 interrupts. Compute the bit offset of the
@@ -291,8 +294,10 @@ static void am33xx_pm_end(void)
                        writel_relaxed(1 << (retrigger_irq & 31),
                                       gic_dist_base + GIC_INT_SET_PENDING_BASE
                                       + retrigger_irq / 32 * 4);
-                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
-                                          (void *)&val);
+               }
+
+               nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
+                                  (void *)&val);
        }
 
        rtc_only_idle = 0;
@@ -415,7 +420,7 @@ static int am33xx_pm_rtc_setup(void)
 
                nvmem = devm_nvmem_device_get(&omap_rtc->dev,
                                              "omap_rtc_scratch0");
-               if (nvmem) {
+               if (!IS_ERR(nvmem)) {
                        nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
                                          4, (void *)&rtc_magic_val);
                        if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC)
index 3a01cfd..f518273 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 menuconfig SOUNDWIRE
-       bool "SoundWire support"
+       tristate "SoundWire support"
        help
          SoundWire is a 2-Pin interface with data and clock line ratified
          by the MIPI Alliance. SoundWire is used for transporting data
@@ -17,17 +17,12 @@ if SOUNDWIRE
 
 comment "SoundWire Devices"
 
-config SOUNDWIRE_BUS
-       tristate
-       select REGMAP_SOUNDWIRE
-
 config SOUNDWIRE_CADENCE
        tristate
 
 config SOUNDWIRE_INTEL
        tristate "Intel SoundWire Master driver"
        select SOUNDWIRE_CADENCE
-       select SOUNDWIRE_BUS
        depends on X86 && ACPI && SND_SOC
        help
          SoundWire Intel Master driver.
index fd99a83..45b7e50 100644 (file)
@@ -5,7 +5,7 @@
 
 #Bus Objs
 soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
-obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o
+obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o
 
 #Cadence Objs
 soundwire-cadence-objs := cadence_master.o
index ff4badc..60e8bde 100644 (file)
@@ -81,8 +81,8 @@
 
 #define CDNS_MCP_INTSET                                0x4C
 
-#define CDNS_SDW_SLAVE_STAT                    0x50
-#define CDNS_MCP_SLAVE_STAT_MASK               BIT(1, 0)
+#define CDNS_MCP_SLAVE_STAT                    0x50
+#define CDNS_MCP_SLAVE_STAT_MASK               GENMASK(1, 0)
 
 #define CDNS_MCP_SLAVE_INTSTAT0                        0x54
 #define CDNS_MCP_SLAVE_INTSTAT1                        0x58
@@ -96,8 +96,8 @@
 #define CDNS_MCP_SLAVE_INTMASK0                        0x5C
 #define CDNS_MCP_SLAVE_INTMASK1                        0x60
 
-#define CDNS_MCP_SLAVE_INTMASK0_MASK           GENMASK(30, 0)
-#define CDNS_MCP_SLAVE_INTMASK1_MASK           GENMASK(16, 0)
+#define CDNS_MCP_SLAVE_INTMASK0_MASK           GENMASK(31, 0)
+#define CDNS_MCP_SLAVE_INTMASK1_MASK           GENMASK(15, 0)
 
 #define CDNS_MCP_PORT_INTSTAT                  0x64
 #define CDNS_MCP_PDI_STAT                      0x6C
index 3a1d8f1..6ee514f 100644 (file)
@@ -433,6 +433,16 @@ config SPI_MT7621
        help
          This selects a driver for the MediaTek MT7621 SPI Controller.
 
+config SPI_NPCM_FIU
+       tristate "Nuvoton NPCM FLASH Interface Unit"
+       depends on ARCH_NPCM || COMPILE_TEST
+       depends on OF && HAS_IOMEM
+       help
+         This enables support for the Flash Interface Unit SPI controller
+         in master mode.
+         This driver does not support generic SPI. The implementation only
+         supports spi-mem interface.
+
 config SPI_NPCM_PSPI
        tristate "Nuvoton NPCM PSPI Controller"
        depends on ARCH_NPCM || COMPILE_TEST
index 63dcab5..adbebee 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
 obj-$(CONFIG_SPI_MT7621)               += spi-mt7621.o
 obj-$(CONFIG_SPI_MXIC)                 += spi-mxic.o
 obj-$(CONFIG_SPI_MXS)                  += spi-mxs.o
+obj-$(CONFIG_SPI_NPCM_FIU)             += spi-npcm-fiu.o
 obj-$(CONFIG_SPI_NPCM_PSPI)            += spi-npcm-pspi.o
 obj-$(CONFIG_SPI_NUC900)               += spi-nuc900.o
 obj-$(CONFIG_SPI_NXP_FLEXSPI)          += spi-nxp-fspi.o
index 6a7d7b5..fd8007e 100644 (file)
@@ -526,7 +526,6 @@ static int atmel_qspi_probe(struct platform_device *pdev)
        /* Request the IRQ */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ\n");
                err = irq;
                goto disable_qspick;
        }
index ea160f1..41d71ba 100644 (file)
@@ -170,7 +170,6 @@ static int altera_spi_probe(struct platform_device *pdev)
 {
        struct altera_spi *hw;
        struct spi_master *master;
-       struct resource *res;
        int err = -ENODEV;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
@@ -189,8 +188,7 @@ static int altera_spi_probe(struct platform_device *pdev)
        hw = spi_master_get_devdata(master);
 
        /* find and map our resources */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->base = devm_ioremap_resource(&pdev->dev, res);
+       hw->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->base)) {
                err = PTR_ERR(hw->base);
                goto exit;
index 0328883..e450ee1 100644 (file)
@@ -817,7 +817,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *of_node = dev->of_node;
-       struct resource *res;
        struct spi_master *master;
        struct a3700_spi *spi;
        u32 num_cs = 0;
@@ -855,8 +854,7 @@ static int a3700_spi_probe(struct platform_device *pdev)
 
        spi->master = master;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spi->base = devm_ioremap_resource(dev, res);
+       spi->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spi->base)) {
                ret = PTR_ERR(spi->base);
                goto error;
@@ -864,7 +862,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(dev, "could not get irq: %d\n", irq);
                ret = -ENXIO;
                goto error;
        }
index 032a615..eb9a243 100644 (file)
@@ -139,7 +139,6 @@ static int ath79_spi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct ath79_spi *sp;
        struct ath79_spi_platform_data *pdata;
-       struct resource *r;
        unsigned long rate;
        int ret;
 
@@ -169,8 +168,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
        sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
        sp->bitbang.flags = SPI_CS_HIGH;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sp->base = devm_ioremap_resource(&pdev->dev, r);
+       sp->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sp->base)) {
                ret = PTR_ERR(sp->base);
                goto err_put_master;
index f00b367..acf318e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
+#include <trace/events/spi.h>
 
 /* SPI register offsets */
 #define SPI_CR                                 0x0000
@@ -1409,9 +1410,13 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
        msg->actual_length = 0;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               trace_spi_transfer_start(msg, xfer);
+
                ret = atmel_spi_one_transfer(master, msg, xfer);
                if (ret)
                        goto msg_done;
+
+               trace_spi_transfer_stop(msg, xfer);
        }
 
        if (as->use_pdc)
index 3b1833e..74842f6 100644 (file)
@@ -460,7 +460,6 @@ static int spi_engine_probe(struct platform_device *pdev)
        struct spi_engine *spi_engine;
        struct spi_master *master;
        unsigned int version;
-       struct resource *res;
        int irq;
        int ret;
 
@@ -480,8 +479,7 @@ static int spi_engine_probe(struct platform_device *pdev)
 
        spin_lock_init(&spi_engine->lock);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spi_engine->base = devm_ioremap_resource(&pdev->dev, res);
+       spi_engine->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spi_engine->base)) {
                ret = PTR_ERR(spi_engine->base);
                goto err_put_master;
index 902bdbf..7a35318 100644 (file)
@@ -343,7 +343,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
 {
        int bpc = 0, bpp = 0;
        u8 command = op->cmd.opcode;
-       int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
+       int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
        int addrlen = op->addr.nbytes;
        int flex_mode = 1;
 
@@ -897,6 +897,7 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
 
                read_from_hw(qspi, slots);
        }
+       bcm_qspi_enable_bspi(qspi);
 
        return 0;
 }
@@ -981,7 +982,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
        if (mspi_read)
                return bcm_qspi_mspi_exec_mem_op(spi, op);
 
-       ret = bcm_qspi_bspi_set_mode(qspi, op, -1);
+       ret = bcm_qspi_bspi_set_mode(qspi, op, 0);
 
        if (!ret)
                ret = bcm_qspi_bspi_exec_mem_op(spi, op);
index 840b1b8..b4070c0 100644 (file)
@@ -25,7 +25,9 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h> /* FIXME: using chip internals */
+#include <linux/gpio/driver.h> /* FIXME: using chip internals */
 #include <linux/of_irq.h>
 #include <linux/spi/spi.h>
 
@@ -66,6 +68,7 @@
 #define BCM2835_SPI_FIFO_SIZE          64
 #define BCM2835_SPI_FIFO_SIZE_3_4      48
 #define BCM2835_SPI_DMA_MIN_LENGTH     96
+#define BCM2835_SPI_NUM_CS             3   /* raise as necessary */
 #define BCM2835_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
                                | SPI_NO_CS | SPI_3WIRE)
 
@@ -92,7 +95,8 @@ MODULE_PARM_DESC(polling_limit_us,
  * @rx_prologue: bytes received without DMA if first RX sglist entry's
  *     length is not a multiple of 4 (to overcome hardware limitation)
  * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
- * @dma_pending: whether a DMA transfer is in progress
+ * @prepare_cs: precalculated CS register value for ->prepare_message()
+ *     (uses slave-specific clock polarity and phase settings)
  * @debugfs_dir: the debugfs directory - neede to remove debugfs when
  *      unloading the module
  * @count_transfer_polling: count of how often polling mode is used
@@ -102,6 +106,19 @@ MODULE_PARM_DESC(polling_limit_us,
  *      These are counted as well in @count_transfer_polling and
  *      @count_transfer_irq
  * @count_transfer_dma: count how often dma mode is used
+ * @chip_select: SPI slave currently selected
+ *     (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs)
+ * @tx_dma_active: whether a TX DMA descriptor is in progress
+ * @rx_dma_active: whether a RX DMA descriptor is in progress
+ *     (used by bcm2835_spi_dma_tx_done() to handle a race)
+ * @fill_tx_desc: preallocated TX DMA descriptor used for RX-only transfers
+ *     (cyclically copies from zero page to TX FIFO)
+ * @fill_tx_addr: bus address of zero page
+ * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
+ *     (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
+ * @clear_rx_addr: bus address of @clear_rx_cs
+ * @clear_rx_cs: precalculated CS register value to clear RX FIFO
+ *     (uses slave-specific clock polarity and phase settings)
  */
 struct bcm2835_spi {
        void __iomem *regs;
@@ -115,13 +132,22 @@ struct bcm2835_spi {
        int tx_prologue;
        int rx_prologue;
        unsigned int tx_spillover;
-       unsigned int dma_pending;
+       u32 prepare_cs[BCM2835_SPI_NUM_CS];
 
        struct dentry *debugfs_dir;
        u64 count_transfer_polling;
        u64 count_transfer_irq;
        u64 count_transfer_irq_after_polling;
        u64 count_transfer_dma;
+
+       u8 chip_select;
+       unsigned int tx_dma_active;
+       unsigned int rx_dma_active;
+       struct dma_async_tx_descriptor *fill_tx_desc;
+       dma_addr_t fill_tx_addr;
+       struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS];
+       dma_addr_t clear_rx_addr;
+       u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned;
 };
 
 #if defined(CONFIG_DEBUG_FS)
@@ -319,6 +345,13 @@ static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
                BCM2835_SPI_CS_INTD |
                BCM2835_SPI_CS_DMAEN |
                BCM2835_SPI_CS_TA);
+       /*
+        * Transmission sometimes breaks unless the DONE bit is written at the
+        * end of every transfer.  The spec says it's a RO bit.  Either the
+        * spec is wrong and the bit is actually of type RW1C, or it's a
+        * hardware erratum.
+        */
+       cs |= BCM2835_SPI_CS_DONE;
        /* and reset RX/TX FIFOS */
        cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX;
 
@@ -448,14 +481,14 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
        bs->rx_prologue  = 0;
        bs->tx_spillover = false;
 
-       if (!sg_is_last(&tfr->tx_sg.sgl[0]))
+       if (bs->tx_buf && !sg_is_last(&tfr->tx_sg.sgl[0]))
                bs->tx_prologue = sg_dma_len(&tfr->tx_sg.sgl[0]) & 3;
 
-       if (!sg_is_last(&tfr->rx_sg.sgl[0])) {
+       if (bs->rx_buf && !sg_is_last(&tfr->rx_sg.sgl[0])) {
                bs->rx_prologue = sg_dma_len(&tfr->rx_sg.sgl[0]) & 3;
 
                if (bs->rx_prologue > bs->tx_prologue) {
-                       if (sg_is_last(&tfr->tx_sg.sgl[0])) {
+                       if (!bs->tx_buf || sg_is_last(&tfr->tx_sg.sgl[0])) {
                                bs->tx_prologue  = bs->rx_prologue;
                        } else {
                                bs->tx_prologue += 4;
@@ -477,7 +510,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
                bcm2835_wr_fifo_count(bs, bs->rx_prologue);
                bcm2835_wait_tx_fifo_empty(bs);
                bcm2835_rd_fifo_count(bs, bs->rx_prologue);
-               bcm2835_spi_reset_hw(ctlr);
+               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_CLEAR_RX
+                                                 | BCM2835_SPI_CS_CLEAR_TX
+                                                 | BCM2835_SPI_CS_DONE);
 
                dma_sync_single_for_device(ctlr->dma_rx->device->dev,
                                           sg_dma_address(&tfr->rx_sg.sgl[0]),
@@ -487,6 +522,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
                sg_dma_len(&tfr->rx_sg.sgl[0])     -= bs->rx_prologue;
        }
 
+       if (!bs->tx_buf)
+               return;
+
        /*
         * Write remaining TX prologue.  Adjust first entry in TX sglist.
         * Also adjust second entry if prologue spills over to it.
@@ -498,7 +536,8 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
                                                  | BCM2835_SPI_CS_DMAEN);
                bcm2835_wr_fifo_count(bs, tx_remaining);
                bcm2835_wait_tx_fifo_empty(bs);
-               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_CLEAR_TX);
+               bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_CLEAR_TX
+                                                 | BCM2835_SPI_CS_DONE);
        }
 
        if (likely(!bs->tx_spillover)) {
@@ -531,6 +570,9 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
                sg_dma_len(&tfr->rx_sg.sgl[0])     += bs->rx_prologue;
        }
 
+       if (!bs->tx_buf)
+               goto out;
+
        if (likely(!bs->tx_spillover)) {
                sg_dma_address(&tfr->tx_sg.sgl[0]) -= bs->tx_prologue;
                sg_dma_len(&tfr->tx_sg.sgl[0])     += bs->tx_prologue;
@@ -539,32 +581,85 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
                sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4;
                sg_dma_len(&tfr->tx_sg.sgl[1])     += 4;
        }
+out:
+       bs->tx_prologue = 0;
 }
 
-static void bcm2835_spi_dma_done(void *data)
+/**
+ * bcm2835_spi_dma_rx_done() - callback for DMA RX channel
+ * @data: SPI master controller
+ *
+ * Used for bidirectional and RX-only transfers.
+ */
+static void bcm2835_spi_dma_rx_done(void *data)
 {
        struct spi_controller *ctlr = data;
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
-       /* reset fifo and HW */
-       bcm2835_spi_reset_hw(ctlr);
-
-       /* and terminate tx-dma as we do not have an irq for it
+       /* terminate tx-dma as we do not have an irq for it
         * because when the rx dma will terminate and this callback
         * is called the tx-dma must have finished - can't get to this
         * situation otherwise...
         */
-       if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_async(ctlr->dma_tx);
-               bcm2835_spi_undo_prologue(bs);
-       }
+       dmaengine_terminate_async(ctlr->dma_tx);
+       bs->tx_dma_active = false;
+       bs->rx_dma_active = false;
+       bcm2835_spi_undo_prologue(bs);
+
+       /* reset fifo and HW */
+       bcm2835_spi_reset_hw(ctlr);
 
        /* and mark as completed */;
        complete(&ctlr->xfer_completion);
 }
 
+/**
+ * bcm2835_spi_dma_tx_done() - callback for DMA TX channel
+ * @data: SPI master controller
+ *
+ * Used for TX-only transfers.
+ */
+static void bcm2835_spi_dma_tx_done(void *data)
+{
+       struct spi_controller *ctlr = data;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+       /* busy-wait for TX FIFO to empty */
+       while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
+               bcm2835_wr(bs, BCM2835_SPI_CS,
+                          bs->clear_rx_cs[bs->chip_select]);
+
+       bs->tx_dma_active = false;
+       smp_wmb();
+
+       /*
+        * In case of a very short transfer, RX DMA may not have been
+        * issued yet.  The onus is then on bcm2835_spi_transfer_one_dma()
+        * to terminate it immediately after issuing.
+        */
+       if (cmpxchg(&bs->rx_dma_active, true, false))
+               dmaengine_terminate_async(ctlr->dma_rx);
+
+       bcm2835_spi_undo_prologue(bs);
+       bcm2835_spi_reset_hw(ctlr);
+       complete(&ctlr->xfer_completion);
+}
+
+/**
+ * bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist
+ * @ctlr: SPI master controller
+ * @spi: SPI slave
+ * @tfr: SPI transfer
+ * @bs: BCM2835 SPI controller
+ * @is_tx: whether to submit DMA descriptor for TX or RX sglist
+ *
+ * Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr.
+ * Return 0 on success or a negative error number.
+ */
 static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
+                                 struct spi_device *spi,
                                  struct spi_transfer *tfr,
+                                 struct bcm2835_spi *bs,
                                  bool is_tx)
 {
        struct dma_chan *chan;
@@ -581,8 +676,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
                chan  = ctlr->dma_tx;
                nents = tfr->tx_sg.nents;
                sgl   = tfr->tx_sg.sgl;
-               flags = 0 /* no  tx interrupt */;
-
+               flags = tfr->rx_buf ? 0 : DMA_PREP_INTERRUPT;
        } else {
                dir   = DMA_DEV_TO_MEM;
                chan  = ctlr->dma_rx;
@@ -595,10 +689,17 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
        if (!desc)
                return -EINVAL;
 
-       /* set callback for rx */
+       /*
+        * Completion is signaled by the RX channel for bidirectional and
+        * RX-only transfers; else by the TX channel for TX-only transfers.
+        */
        if (!is_tx) {
-               desc->callback = bcm2835_spi_dma_done;
+               desc->callback = bcm2835_spi_dma_rx_done;
+               desc->callback_param = ctlr;
+       } else if (!tfr->rx_buf) {
+               desc->callback = bcm2835_spi_dma_tx_done;
                desc->callback_param = ctlr;
+               bs->chip_select = spi->chip_select;
        }
 
        /* submit it to DMA-engine */
@@ -607,12 +708,60 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
        return dma_submit_error(cookie);
 }
 
+/**
+ * bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
+ * @ctlr: SPI master controller
+ * @spi: SPI slave
+ * @tfr: SPI transfer
+ * @cs: CS register
+ *
+ * For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
+ * the TX and RX DMA channel to copy between memory and FIFO register.
+ *
+ * For *TX-only* transfers (rx_buf is %NULL), copying the RX FIFO's contents to
+ * memory is pointless.  However not reading the RX FIFO isn't an option either
+ * because transmission is halted once it's full.  As a workaround, cyclically
+ * clear the RX FIFO by setting the CLEAR_RX bit in the CS register.
+ *
+ * The CS register value is precalculated in bcm2835_spi_setup().  Normally
+ * this is called only once, on slave registration.  A DMA descriptor to write
+ * this value is preallocated in bcm2835_dma_init().  All that's left to do
+ * when performing a TX-only transfer is to submit this descriptor to the RX
+ * DMA channel.  Latency is thereby minimized.  The descriptor does not
+ * generate any interrupts while running.  It must be terminated once the
+ * TX DMA channel is done.
+ *
+ * Clearing the RX FIFO is paced by the DREQ signal.  The signal is asserted
+ * when the RX FIFO becomes half full, i.e. 32 bytes.  (Tuneable with the DC
+ * register.)  Reading 32 bytes from the RX FIFO would normally require 8 bus
+ * accesses, whereas clearing it requires only 1 bus access.  So an 8-fold
+ * reduction in bus traffic and thus energy consumption is achieved.
+ *
+ * For *RX-only* transfers (tx_buf is %NULL), fill the TX FIFO by cyclically
+ * copying from the zero page.  The DMA descriptor to do this is preallocated
+ * in bcm2835_dma_init().  It must be terminated once the RX DMA channel is
+ * done and can then be reused.
+ *
+ * The BCM2835 DMA driver autodetects when a transaction copies from the zero
+ * page and utilizes the DMA controller's ability to synthesize zeroes instead
+ * of copying them from memory.  This reduces traffic on the memory bus.  The
+ * feature is not available on so-called "lite" channels, but normally TX DMA
+ * is backed by a full-featured channel.
+ *
+ * Zero-filling the TX FIFO is paced by the DREQ signal.  Unfortunately the
+ * BCM2835 SPI controller continues to assert DREQ even after the DLEN register
+ * has been counted down to zero (hardware erratum).  Thus, when the transfer
+ * has finished, the DMA engine zero-fills the TX FIFO until it is half full.
+ * (Tuneable with the DC register.)  So up to 9 gratuitous bus accesses are
+ * performed at the end of an RX-only transfer.
+ */
 static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
                                        u32 cs)
 {
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       dma_cookie_t cookie;
        int ret;
 
        /* update usage statistics */
@@ -625,16 +774,15 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
        bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs);
 
        /* setup tx-DMA */
-       ret = bcm2835_spi_prepare_sg(ctlr, tfr, true);
+       if (bs->tx_buf) {
+               ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true);
+       } else {
+               cookie = dmaengine_submit(bs->fill_tx_desc);
+               ret = dma_submit_error(cookie);
+       }
        if (ret)
                goto err_reset_hw;
 
-       /* start TX early */
-       dma_async_issue_pending(ctlr->dma_tx);
-
-       /* mark as dma pending */
-       bs->dma_pending = 1;
-
        /* set the DMA length */
        bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);
 
@@ -642,20 +790,43 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
        bcm2835_wr(bs, BCM2835_SPI_CS,
                   cs | BCM2835_SPI_CS_TA | BCM2835_SPI_CS_DMAEN);
 
+       bs->tx_dma_active = true;
+       smp_wmb();
+
+       /* start TX early */
+       dma_async_issue_pending(ctlr->dma_tx);
+
        /* setup rx-DMA late - to run transfers while
         * mapping of the rx buffers still takes place
         * this saves 10us or more.
         */
-       ret = bcm2835_spi_prepare_sg(ctlr, tfr, false);
+       if (bs->rx_buf) {
+               ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false);
+       } else {
+               cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]);
+               ret = dma_submit_error(cookie);
+       }
        if (ret) {
                /* need to reset on errors */
                dmaengine_terminate_sync(ctlr->dma_tx);
-               bs->dma_pending = false;
+               bs->tx_dma_active = false;
                goto err_reset_hw;
        }
 
        /* start rx dma late */
        dma_async_issue_pending(ctlr->dma_rx);
+       bs->rx_dma_active = true;
+       smp_mb();
+
+       /*
+        * In case of a very short TX-only transfer, bcm2835_spi_dma_tx_done()
+        * may run before RX DMA is issued.  Terminate RX DMA if so.
+        */
+       if (!bs->rx_buf && !bs->tx_dma_active &&
+           cmpxchg(&bs->rx_dma_active, true, false)) {
+               dmaengine_terminate_async(ctlr->dma_rx);
+               bcm2835_spi_reset_hw(ctlr);
+       }
 
        /* wait for wakeup in framework */
        return 1;
@@ -678,26 +849,52 @@ static bool bcm2835_spi_can_dma(struct spi_controller *ctlr,
        return true;
 }
 
-static void bcm2835_dma_release(struct spi_controller *ctlr)
+static void bcm2835_dma_release(struct spi_controller *ctlr,
+                               struct bcm2835_spi *bs)
 {
+       int i;
+
        if (ctlr->dma_tx) {
                dmaengine_terminate_sync(ctlr->dma_tx);
+
+               if (bs->fill_tx_desc)
+                       dmaengine_desc_free(bs->fill_tx_desc);
+
+               if (bs->fill_tx_addr)
+                       dma_unmap_page_attrs(ctlr->dma_tx->device->dev,
+                                            bs->fill_tx_addr, sizeof(u32),
+                                            DMA_TO_DEVICE,
+                                            DMA_ATTR_SKIP_CPU_SYNC);
+
                dma_release_channel(ctlr->dma_tx);
                ctlr->dma_tx = NULL;
        }
+
        if (ctlr->dma_rx) {
                dmaengine_terminate_sync(ctlr->dma_rx);
+
+               for (i = 0; i < BCM2835_SPI_NUM_CS; i++)
+                       if (bs->clear_rx_desc[i])
+                               dmaengine_desc_free(bs->clear_rx_desc[i]);
+
+               if (bs->clear_rx_addr)
+                       dma_unmap_single(ctlr->dma_rx->device->dev,
+                                        bs->clear_rx_addr,
+                                        sizeof(bs->clear_rx_cs),
+                                        DMA_TO_DEVICE);
+
                dma_release_channel(ctlr->dma_rx);
                ctlr->dma_rx = NULL;
        }
 }
 
-static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev)
+static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
+                            struct bcm2835_spi *bs)
 {
        struct dma_slave_config slave_config;
        const __be32 *addr;
        dma_addr_t dma_reg_base;
-       int ret;
+       int ret, i;
 
        /* base address in dma-space */
        addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
@@ -719,7 +916,11 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev)
                goto err_release;
        }
 
-       /* configure DMAs */
+       /*
+        * The TX DMA channel either copies a transfer's TX buffer to the FIFO
+        * or, in case of an RX-only transfer, cyclically copies from the zero
+        * page to the FIFO using a preallocated, reusable descriptor.
+        */
        slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
        slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
@@ -727,17 +928,74 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev)
        if (ret)
                goto err_config;
 
+       bs->fill_tx_addr = dma_map_page_attrs(ctlr->dma_tx->device->dev,
+                                             ZERO_PAGE(0), 0, sizeof(u32),
+                                             DMA_TO_DEVICE,
+                                             DMA_ATTR_SKIP_CPU_SYNC);
+       if (dma_mapping_error(ctlr->dma_tx->device->dev, bs->fill_tx_addr)) {
+               dev_err(dev, "cannot map zero page - not using DMA mode\n");
+               bs->fill_tx_addr = 0;
+               goto err_release;
+       }
+
+       bs->fill_tx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_tx,
+                                                    bs->fill_tx_addr,
+                                                    sizeof(u32), 0,
+                                                    DMA_MEM_TO_DEV, 0);
+       if (!bs->fill_tx_desc) {
+               dev_err(dev, "cannot prepare fill_tx_desc - not using DMA mode\n");
+               goto err_release;
+       }
+
+       ret = dmaengine_desc_set_reuse(bs->fill_tx_desc);
+       if (ret) {
+               dev_err(dev, "cannot reuse fill_tx_desc - not using DMA mode\n");
+               goto err_release;
+       }
+
+       /*
+        * The RX DMA channel is used bidirectionally:  It either reads the
+        * RX FIFO or, in case of a TX-only transfer, cyclically writes a
+        * precalculated value to the CS register to clear the RX FIFO.
+        */
        slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
        slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_CS);
+       slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config);
        if (ret)
                goto err_config;
 
+       bs->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
+                                          bs->clear_rx_cs,
+                                          sizeof(bs->clear_rx_cs),
+                                          DMA_TO_DEVICE);
+       if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) {
+               dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n");
+               bs->clear_rx_addr = 0;
+               goto err_release;
+       }
+
+       for (i = 0; i < BCM2835_SPI_NUM_CS; i++) {
+               bs->clear_rx_desc[i] = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
+                                          bs->clear_rx_addr + i * sizeof(u32),
+                                          sizeof(u32), 0,
+                                          DMA_MEM_TO_DEV, 0);
+               if (!bs->clear_rx_desc[i]) {
+                       dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n");
+                       goto err_release;
+               }
+
+               ret = dmaengine_desc_set_reuse(bs->clear_rx_desc[i]);
+               if (ret) {
+                       dev_err(dev, "cannot reuse clear_rx_desc - not using DMA mode\n");
+                       goto err_release;
+               }
+       }
+
        /* all went well, so set can_dma */
        ctlr->can_dma = bcm2835_spi_can_dma;
-       /* need to do TX AND RX DMA, so we need dummy buffers */
-       ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
 
        return;
 
@@ -745,7 +1003,7 @@ err_config:
        dev_err(dev, "issue configuring dma: %d - not using DMA mode\n",
                ret);
 err_release:
-       bcm2835_dma_release(ctlr);
+       bcm2835_dma_release(ctlr, bs);
 err:
        return;
 }
@@ -812,7 +1070,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        unsigned long spi_hz, clk_hz, cdiv, spi_used_hz;
        unsigned long hz_per_byte, byte_limit;
-       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+       u32 cs = bs->prepare_cs[spi->chip_select];
 
        /* set clock */
        spi_hz = tfr->speed_hz;
@@ -834,18 +1092,8 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
        bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
 
        /* handle all the 3-wire mode */
-       if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
-           tfr->rx_buf != ctlr->dummy_rx)
+       if (spi->mode & SPI_3WIRE && tfr->rx_buf)
                cs |= BCM2835_SPI_CS_REN;
-       else
-               cs &= ~BCM2835_SPI_CS_REN;
-
-       /*
-        * The driver always uses software-controlled GPIO Chip Select.
-        * Set the hardware-controlled native Chip Select to an invalid
-        * value to prevent it from interfering.
-        */
-       cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
 
        /* set transmit buffers and length */
        bs->tx_buf = tfr->tx_buf;
@@ -882,7 +1130,6 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
 {
        struct spi_device *spi = msg->spi;
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
-       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
        int ret;
 
        if (ctlr->can_dma) {
@@ -897,14 +1144,11 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
                        return ret;
        }
 
-       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);
+       /*
+        * Set up clock polarity before spi_transfer_one_message() asserts
+        * chip select to avoid a gratuitous clock signal edge.
+        */
+       bcm2835_wr(bs, BCM2835_SPI_CS, bs->prepare_cs[spi->chip_select]);
 
        return 0;
 }
@@ -915,11 +1159,12 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* if an error occurred and we have an active dma, then terminate */
-       if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_sync(ctlr->dma_tx);
-               dmaengine_terminate_sync(ctlr->dma_rx);
-               bcm2835_spi_undo_prologue(bs);
-       }
+       dmaengine_terminate_sync(ctlr->dma_tx);
+       bs->tx_dma_active = false;
+       dmaengine_terminate_sync(ctlr->dma_rx);
+       bs->rx_dma_active = false;
+       bcm2835_spi_undo_prologue(bs);
+
        /* and reset */
        bcm2835_spi_reset_hw(ctlr);
 }
@@ -931,14 +1176,50 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
 
 static int bcm2835_spi_setup(struct spi_device *spi)
 {
-       int err;
+       struct spi_controller *ctlr = spi->controller;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        struct gpio_chip *chip;
+       enum gpio_lookup_flags lflags;
+       u32 cs;
+
+       /*
+        * Precalculate SPI slave's CS register value for ->prepare_message():
+        * The driver always uses software-controlled GPIO chip select, hence
+        * set the hardware-controlled native chip select to an invalid value
+        * to prevent it from interfering.
+        */
+       cs = BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
+       if (spi->mode & SPI_CPOL)
+               cs |= BCM2835_SPI_CS_CPOL;
+       if (spi->mode & SPI_CPHA)
+               cs |= BCM2835_SPI_CS_CPHA;
+       bs->prepare_cs[spi->chip_select] = cs;
+
+       /*
+        * Precalculate SPI slave's CS register value to clear RX FIFO
+        * in case of a TX-only DMA transfer.
+        */
+       if (ctlr->dma_rx) {
+               bs->clear_rx_cs[spi->chip_select] = cs |
+                                                   BCM2835_SPI_CS_TA |
+                                                   BCM2835_SPI_CS_DMAEN |
+                                                   BCM2835_SPI_CS_CLEAR_RX;
+               dma_sync_single_for_device(ctlr->dma_rx->device->dev,
+                                          bs->clear_rx_addr,
+                                          sizeof(bs->clear_rx_cs),
+                                          DMA_TO_DEVICE);
+       }
+
        /*
         * sanity checking the native-chipselects
         */
        if (spi->mode & SPI_NO_CS)
                return 0;
-       if (gpio_is_valid(spi->cs_gpio))
+       /*
+        * The SPI core has successfully requested the CS GPIO line from the
+        * device tree, so we are done.
+        */
+       if (spi->cs_gpiod)
                return 0;
        if (spi->chip_select > 1) {
                /* error in the case of native CS requested with CS > 1
@@ -949,29 +1230,43 @@ static int bcm2835_spi_setup(struct spi_device *spi)
                        "setup: only two native chip-selects are supported\n");
                return -EINVAL;
        }
-       /* now translate native cs to GPIO */
+
+       /*
+        * Translate native CS to GPIO
+        *
+        * FIXME: poking around in the gpiolib internals like this is
+        * not very good practice. Find a way to locate the real problem
+        * and fix it. Why is the GPIO descriptor in spi->cs_gpiod
+        * sometimes not assigned correctly? Erroneous device trees?
+        */
 
        /* get the gpio chip for the base */
        chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
        if (!chip)
                return 0;
 
-       /* and calculate the real CS */
-       spi->cs_gpio = chip->base + 8 - spi->chip_select;
+       /*
+        * Retrieve the corresponding GPIO line used for CS.
+        * The inversion semantics will be handled by the GPIO core
+        * code, so we pass GPIOS_OUT_LOW for "unasserted" and
+        * the correct flag for inversion semantics. The SPI_CS_HIGH
+        * on spi->mode cannot be checked for polarity in this case
+        * as the flag use_gpio_descriptors enforces SPI_CS_HIGH.
+        */
+       if (of_property_read_bool(spi->dev.of_node, "spi-cs-high"))
+               lflags = GPIO_ACTIVE_HIGH;
+       else
+               lflags = GPIO_ACTIVE_LOW;
+       spi->cs_gpiod = gpiochip_request_own_desc(chip, 8 - spi->chip_select,
+                                                 DRV_NAME,
+                                                 lflags,
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(spi->cs_gpiod))
+               return PTR_ERR(spi->cs_gpiod);
 
        /* and set up the "mode" and level */
-       dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n",
-                spi->chip_select, spi->cs_gpio);
-
-       /* set up GPIO as output and pull to the correct level */
-       err = gpio_direction_output(spi->cs_gpio,
-                                   (spi->mode & SPI_CS_HIGH) ? 0 : 1);
-       if (err) {
-               dev_err(&spi->dev,
-                       "could not set CS%i gpio %i as output: %i",
-                       spi->chip_select, spi->cs_gpio, err);
-               return err;
-       }
+       dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
+                spi->chip_select);
 
        return 0;
 }
@@ -980,18 +1275,19 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 {
        struct spi_controller *ctlr;
        struct bcm2835_spi *bs;
-       struct resource *res;
        int err;
 
-       ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs));
+       ctlr = spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
+                                                 dma_get_cache_alignment()));
        if (!ctlr)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, ctlr);
 
+       ctlr->use_gpio_descriptors = true;
        ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
        ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
-       ctlr->num_chipselect = 3;
+       ctlr->num_chipselect = BCM2835_SPI_NUM_CS;
        ctlr->setup = bcm2835_spi_setup;
        ctlr->transfer_one = bcm2835_spi_transfer_one;
        ctlr->handle_err = bcm2835_spi_handle_err;
@@ -1000,8 +1296,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        bs = spi_controller_get_devdata(ctlr);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bs->regs = devm_ioremap_resource(&pdev->dev, res);
+       bs->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(bs->regs)) {
                err = PTR_ERR(bs->regs);
                goto out_controller_put;
@@ -1016,14 +1311,13 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        bs->irq = platform_get_irq(pdev, 0);
        if (bs->irq <= 0) {
-               dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
                err = bs->irq ? bs->irq : -ENODEV;
                goto out_controller_put;
        }
 
        clk_prepare_enable(bs->clk);
 
-       bcm2835_dma_init(ctlr, &pdev->dev);
+       bcm2835_dma_init(ctlr, &pdev->dev, bs);
 
        /* initialise the hardware with the default polarities */
        bcm2835_wr(bs, BCM2835_SPI_CS,
@@ -1067,7 +1361,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(bs->clk);
 
-       bcm2835_dma_release(ctlr);
+       bcm2835_dma_release(ctlr, bs);
 
        return 0;
 }
index bb57035..a2162ff 100644 (file)
@@ -491,7 +491,6 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct bcm2835aux_spi *bs;
-       struct resource *res;
        unsigned long clk_hz;
        int err;
 
@@ -524,8 +523,7 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
        bs = spi_master_get_devdata(master);
 
        /* the main area */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bs->regs = devm_ioremap_resource(&pdev->dev, res);
+       bs->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(bs->regs)) {
                err = PTR_ERR(bs->regs);
                goto out_master_put;
@@ -540,7 +538,6 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
 
        bs->irq = platform_get_irq(pdev, 0);
        if (bs->irq <= 0) {
-               dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
                err = bs->irq ? bs->irq : -ENODEV;
                goto out_master_put;
        }
index 9a06ffd..c6836a9 100644 (file)
@@ -330,7 +330,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct bcm63xx_hsspi *bs;
-       struct resource *res_mem;
        void __iomem *regs;
        struct device *dev = &pdev->dev;
        struct clk *clk, *pll_clk = NULL;
@@ -338,13 +337,10 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
        u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "no irq: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(dev, res_mem);
+       regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
index df1c94a..fdd7eaa 100644 (file)
@@ -520,10 +520,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "no irq: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        clk = devm_clk_get(dev, "spi");
        if (IS_ERR(clk)) {
index 7c41e4e..c36587b 100644 (file)
@@ -474,7 +474,6 @@ static int cdns_spi_probe(struct platform_device *pdev)
        int ret = 0, irq;
        struct spi_master *master;
        struct cdns_spi *xspi;
-       struct resource *res;
        u32 num_cs;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*xspi));
@@ -485,8 +484,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
        master->dev.of_node = pdev->dev.of_node;
        platform_set_drvdata(pdev, master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xspi->regs = devm_ioremap_resource(&pdev->dev, res);
+       xspi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xspi->regs)) {
                ret = PTR_ERR(xspi->regs);
                goto remove_master;
@@ -540,7 +538,6 @@ static int cdns_spi_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq <= 0) {
                ret = -ENXIO;
-               dev_err(&pdev->dev, "irq number is invalid\n");
                goto clk_dis_all;
        }
 
index ee4703e..1a2de6c 100644 (file)
@@ -18,7 +18,6 @@
 
 static int octeon_spi_probe(struct platform_device *pdev)
 {
-       struct resource *res_mem;
        void __iomem *reg_base;
        struct spi_master *master;
        struct octeon_spi *p;
@@ -30,8 +29,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
        p = spi_master_get_devdata(master);
        platform_set_drvdata(pdev, master);
 
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
+       reg_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(reg_base)) {
                err = PTR_ERR(reg_base);
                goto fail;
index 4daba12..5e900f2 100644 (file)
@@ -91,7 +91,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
 {
        struct spi_clps711x_data *hw;
        struct spi_master *master;
-       struct resource *res;
        int irq, ret;
 
        irq = platform_get_irq(pdev, 0);
@@ -125,8 +124,7 @@ static int spi_clps711x_probe(struct platform_device *pdev)
                goto err_out;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->syncio = devm_ioremap_resource(&pdev->dev, res);
+       hw->syncio = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->syncio)) {
                ret = PTR_ERR(hw->syncio);
                goto err_out;
index 5ff48ab..f80e06c 100644 (file)
@@ -339,7 +339,6 @@ static int mcfqspi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct mcfqspi *mcfqspi;
-       struct resource *res;
        struct mcfqspi_platform_data *pdata;
        int status;
 
@@ -362,8 +361,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
 
        mcfqspi = spi_master_get_devdata(master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mcfqspi->iobase = devm_ioremap_resource(&pdev->dev, res);
+       mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mcfqspi->iobase)) {
                status = PTR_ERR(mcfqspi->iobase);
                goto fail0;
index 18c0656..bd46fca 100644 (file)
@@ -79,14 +79,12 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
                            const char *cpu_syscon, u32 if_si_owner_offset)
 {
        struct dw_spi_mscc *dwsmscc;
-       struct resource *res;
 
        dwsmscc = devm_kzalloc(&pdev->dev, sizeof(*dwsmscc), GFP_KERNEL);
        if (!dwsmscc)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       dwsmscc->spi_mst = devm_ioremap_resource(&pdev->dev, res);
+       dwsmscc->spi_mst = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(dwsmscc->spi_mst)) {
                dev_err(&pdev->dev, "SPI_MST region map failed\n");
                return PTR_ERR(dwsmscc->spi_mst);
@@ -138,7 +136,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
                         struct dw_spi_mmio *dwsmmio);
        struct dw_spi_mmio *dwsmmio;
        struct dw_spi *dws;
-       struct resource *mem;
        int ret;
        int num_cs;
 
@@ -150,18 +147,15 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
        dws = &dwsmmio->dws;
 
        /* Get basic io resource and map it */
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dws->regs = devm_ioremap_resource(&pdev->dev, mem);
+       dws->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(dws->regs)) {
                dev_err(&pdev->dev, "SPI region map failed\n");
                return PTR_ERR(dws->regs);
        }
 
        dws->irq = platform_get_irq(pdev, 0);
-       if (dws->irq < 0) {
-               dev_err(&pdev->dev, "no irq resource?\n");
+       if (dws->irq < 0)
                return dws->irq; /* -ENXIO */
-       }
 
        dwsmmio->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dwsmmio->clk))
@@ -172,8 +166,10 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
 
        /* Optional clock needed to access the registers */
        dwsmmio->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
-       if (IS_ERR(dwsmmio->pclk))
-               return PTR_ERR(dwsmmio->pclk);
+       if (IS_ERR(dwsmmio->pclk)) {
+               ret = PTR_ERR(dwsmmio->pclk);
+               goto out_clk;
+       }
        ret = clk_prepare_enable(dwsmmio->pclk);
        if (ret)
                goto out_clk;
index 9651679..1406449 100644 (file)
@@ -19,6 +19,7 @@ struct spi_pci_desc {
        int     (*setup)(struct dw_spi *);
        u16     num_cs;
        u16     bus_num;
+       u32     max_freq;
 };
 
 static struct spi_pci_desc spi_pci_mid_desc_1 = {
@@ -33,6 +34,12 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = {
        .bus_num = 1,
 };
 
+static struct spi_pci_desc spi_pci_ehl_desc = {
+       .num_cs = 1,
+       .bus_num = -1,
+       .max_freq = 100000000,
+};
+
 static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct dw_spi *dws;
@@ -65,6 +72,7 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (desc) {
                dws->num_cs = desc->num_cs;
                dws->bus_num = desc->bus_num;
+               dws->max_freq = desc->max_freq;
 
                if (desc->setup) {
                        ret = desc->setup(dws);
@@ -98,16 +106,14 @@ static void spi_pci_remove(struct pci_dev *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int spi_suspend(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct dw_spi *dws = pci_get_drvdata(pdev);
+       struct dw_spi *dws = dev_get_drvdata(dev);
 
        return dw_spi_suspend_host(dws);
 }
 
 static int spi_resume(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct dw_spi *dws = pci_get_drvdata(pdev);
+       struct dw_spi *dws = dev_get_drvdata(dev);
 
        return dw_spi_resume_host(dws);
 }
@@ -125,8 +131,14 @@ static const struct pci_device_id pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1},
        /* Intel MID platform SPI controller 2 */
        { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2},
+       /* Intel Elkhart Lake PSE SPI controllers */
+       { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc},
+       { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc},
+       { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc},
+       { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&spi_pci_ehl_desc},
        {},
 };
+MODULE_DEVICE_TABLE(pci, pci_ids);
 
 static struct pci_driver dw_spi_driver = {
        .name =         DRIVER_NAME,
index eb1f214..64d4c44 100644 (file)
@@ -400,10 +400,8 @@ static int efm32_spi_probe(struct platform_device *pdev)
        }
 
        ret = platform_get_irq(pdev, 0);
-       if (ret <= 0) {
-               dev_err(&pdev->dev, "failed to get rx irq (%d)\n", ret);
+       if (ret <= 0)
                goto err;
-       }
 
        ddata->rxirq = ret;
 
index 4034e3e..4e1ccd4 100644 (file)
@@ -656,10 +656,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get irq resources\n");
+       if (irq < 0)
                return -EBUSY;
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
index e967ac5..858f054 100644 (file)
@@ -305,12 +305,10 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
        }
 
        if (mspi->flags & SPI_CPM1) {
-               struct resource *res;
                void *pram;
 
-               res = platform_get_resource(to_platform_device(dev),
-                                           IORESOURCE_MEM, 1);
-               pram = devm_ioremap_resource(dev, res);
+               pram = devm_platform_ioremap_resource(to_platform_device(dev),
+                                                     1);
                if (IS_ERR(pram))
                        mspi->pram = NULL;
                else
index 53335cc..bec758e 100644 (file)
@@ -9,26 +9,16 @@
 #include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/errno.h>
 #include <linux/interrupt.h>
-#include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/math64.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
-#include <linux/sched.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi-fsl-dspi.h>
-#include <linux/spi/spi_bitbang.h>
-#include <linux/time.h>
 
-#define DRIVER_NAME "fsl-dspi"
+#define DRIVER_NAME                    "fsl-dspi"
 
 #ifdef CONFIG_M5441x
 #define DSPI_FIFO_SIZE                 16
 #endif
 #define DSPI_DMA_BUFSIZE               (DSPI_FIFO_SIZE * 1024)
 
-#define SPI_MCR                0x00
-#define SPI_MCR_MASTER         (1 << 31)
-#define SPI_MCR_PCSIS          (0x3F << 16)
-#define SPI_MCR_CLR_TXF        (1 << 11)
-#define SPI_MCR_CLR_RXF        (1 << 10)
-#define SPI_MCR_XSPI           (1 << 3)
-
-#define SPI_TCR                        0x08
-#define SPI_TCR_GET_TCNT(x)    (((x) & 0xffff0000) >> 16)
-
-#define SPI_CTAR(x)            (0x0c + (((x) & 0x3) * 4))
-#define SPI_CTAR_FMSZ(x)       (((x) & 0x0000000f) << 27)
-#define SPI_CTAR_CPOL(x)       ((x) << 26)
-#define SPI_CTAR_CPHA(x)       ((x) << 25)
-#define SPI_CTAR_LSBFE(x)      ((x) << 24)
-#define SPI_CTAR_PCSSCK(x)     (((x) & 0x00000003) << 22)
-#define SPI_CTAR_PASC(x)       (((x) & 0x00000003) << 20)
-#define SPI_CTAR_PDT(x)        (((x) & 0x00000003) << 18)
-#define SPI_CTAR_PBR(x)        (((x) & 0x00000003) << 16)
-#define SPI_CTAR_CSSCK(x)      (((x) & 0x0000000f) << 12)
-#define SPI_CTAR_ASC(x)        (((x) & 0x0000000f) << 8)
-#define SPI_CTAR_DT(x)         (((x) & 0x0000000f) << 4)
-#define SPI_CTAR_BR(x)         ((x) & 0x0000000f)
-#define SPI_CTAR_SCALE_BITS    0xf
-
-#define SPI_CTAR0_SLAVE        0x0c
-
-#define SPI_SR                 0x2c
-#define SPI_SR_EOQF            0x10000000
-#define SPI_SR_TCFQF           0x80000000
-#define SPI_SR_CLEAR           0x9aaf0000
-
-#define SPI_RSER_TFFFE         BIT(25)
-#define SPI_RSER_TFFFD         BIT(24)
-#define SPI_RSER_RFDFE         BIT(17)
-#define SPI_RSER_RFDFD         BIT(16)
-
-#define SPI_RSER               0x30
-#define SPI_RSER_EOQFE         0x10000000
-#define SPI_RSER_TCFQE         0x80000000
-
-#define SPI_PUSHR              0x34
-#define SPI_PUSHR_CMD_CONT     (1 << 15)
-#define SPI_PUSHR_CONT         (SPI_PUSHR_CMD_CONT << 16)
-#define SPI_PUSHR_CMD_CTAS(x)  (((x) & 0x0003) << 12)
-#define SPI_PUSHR_CTAS(x)      (SPI_PUSHR_CMD_CTAS(x) << 16)
-#define SPI_PUSHR_CMD_EOQ      (1 << 11)
-#define SPI_PUSHR_EOQ          (SPI_PUSHR_CMD_EOQ << 16)
-#define SPI_PUSHR_CMD_CTCNT    (1 << 10)
-#define SPI_PUSHR_CTCNT                (SPI_PUSHR_CMD_CTCNT << 16)
-#define SPI_PUSHR_CMD_PCS(x)   ((1 << x) & 0x003f)
-#define SPI_PUSHR_PCS(x)       (SPI_PUSHR_CMD_PCS(x) << 16)
-#define SPI_PUSHR_TXDATA(x)    ((x) & 0x0000ffff)
-
-#define SPI_PUSHR_SLAVE        0x34
-
-#define SPI_POPR               0x38
-#define SPI_POPR_RXDATA(x)     ((x) & 0x0000ffff)
-
-#define SPI_TXFR0              0x3c
-#define SPI_TXFR1              0x40
-#define SPI_TXFR2              0x44
-#define SPI_TXFR3              0x48
-#define SPI_RXFR0              0x7c
-#define SPI_RXFR1              0x80
-#define SPI_RXFR2              0x84
-#define SPI_RXFR3              0x88
-
-#define SPI_CTARE(x)           (0x11c + (((x) & 0x3) * 4))
-#define SPI_CTARE_FMSZE(x)     (((x) & 0x1) << 16)
-#define SPI_CTARE_DTCP(x)      ((x) & 0x7ff)
-
-#define SPI_SREX               0x13c
-
-#define SPI_FRAME_BITS(bits)   SPI_CTAR_FMSZ((bits) - 1)
-#define SPI_FRAME_BITS_MASK    SPI_CTAR_FMSZ(0xf)
-#define SPI_FRAME_BITS_16      SPI_CTAR_FMSZ(0xf)
-#define SPI_FRAME_BITS_8       SPI_CTAR_FMSZ(0x7)
-
-#define SPI_FRAME_EBITS(bits)  SPI_CTARE_FMSZE(((bits) - 1) >> 4)
-#define SPI_FRAME_EBITS_MASK   SPI_CTARE_FMSZE(1)
+#define SPI_MCR                                0x00
+#define SPI_MCR_MASTER                 BIT(31)
+#define SPI_MCR_PCSIS                  (0x3F << 16)
+#define SPI_MCR_CLR_TXF                        BIT(11)
+#define SPI_MCR_CLR_RXF                        BIT(10)
+#define SPI_MCR_XSPI                   BIT(3)
+
+#define SPI_TCR                                0x08
+#define SPI_TCR_GET_TCNT(x)            (((x) & GENMASK(31, 16)) >> 16)
+
+#define SPI_CTAR(x)                    (0x0c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTAR_FMSZ(x)               (((x) << 27) & GENMASK(30, 27))
+#define SPI_CTAR_CPOL                  BIT(26)
+#define SPI_CTAR_CPHA                  BIT(25)
+#define SPI_CTAR_LSBFE                 BIT(24)
+#define SPI_CTAR_PCSSCK(x)             (((x) << 22) & GENMASK(23, 22))
+#define SPI_CTAR_PASC(x)               (((x) << 20) & GENMASK(21, 20))
+#define SPI_CTAR_PDT(x)                        (((x) << 18) & GENMASK(19, 18))
+#define SPI_CTAR_PBR(x)                        (((x) << 16) & GENMASK(17, 16))
+#define SPI_CTAR_CSSCK(x)              (((x) << 12) & GENMASK(15, 12))
+#define SPI_CTAR_ASC(x)                        (((x) << 8) & GENMASK(11, 8))
+#define SPI_CTAR_DT(x)                 (((x) << 4) & GENMASK(7, 4))
+#define SPI_CTAR_BR(x)                 ((x) & GENMASK(3, 0))
+#define SPI_CTAR_SCALE_BITS            0xf
+
+#define SPI_CTAR0_SLAVE                        0x0c
+
+#define SPI_SR                         0x2c
+#define SPI_SR_TCFQF                   BIT(31)
+#define SPI_SR_EOQF                    BIT(28)
+#define SPI_SR_TFUF                    BIT(27)
+#define SPI_SR_TFFF                    BIT(25)
+#define SPI_SR_CMDTCF                  BIT(23)
+#define SPI_SR_SPEF                    BIT(21)
+#define SPI_SR_RFOF                    BIT(19)
+#define SPI_SR_TFIWF                   BIT(18)
+#define SPI_SR_RFDF                    BIT(17)
+#define SPI_SR_CMDFFF                  BIT(16)
+#define SPI_SR_CLEAR                   (SPI_SR_TCFQF | SPI_SR_EOQF | \
+                                       SPI_SR_TFUF | SPI_SR_TFFF | \
+                                       SPI_SR_CMDTCF | SPI_SR_SPEF | \
+                                       SPI_SR_RFOF | SPI_SR_TFIWF | \
+                                       SPI_SR_RFDF | SPI_SR_CMDFFF)
+
+#define SPI_RSER_TFFFE                 BIT(25)
+#define SPI_RSER_TFFFD                 BIT(24)
+#define SPI_RSER_RFDFE                 BIT(17)
+#define SPI_RSER_RFDFD                 BIT(16)
+
+#define SPI_RSER                       0x30
+#define SPI_RSER_TCFQE                 BIT(31)
+#define SPI_RSER_EOQFE                 BIT(28)
+
+#define SPI_PUSHR                      0x34
+#define SPI_PUSHR_CMD_CONT             BIT(15)
+#define SPI_PUSHR_CMD_CTAS(x)          (((x) << 12 & GENMASK(14, 12)))
+#define SPI_PUSHR_CMD_EOQ              BIT(11)
+#define SPI_PUSHR_CMD_CTCNT            BIT(10)
+#define SPI_PUSHR_CMD_PCS(x)           (BIT(x) & GENMASK(5, 0))
+
+#define SPI_PUSHR_SLAVE                        0x34
+
+#define SPI_POPR                       0x38
+
+#define SPI_TXFR0                      0x3c
+#define SPI_TXFR1                      0x40
+#define SPI_TXFR2                      0x44
+#define SPI_TXFR3                      0x48
+#define SPI_RXFR0                      0x7c
+#define SPI_RXFR1                      0x80
+#define SPI_RXFR2                      0x84
+#define SPI_RXFR3                      0x88
+
+#define SPI_CTARE(x)                   (0x11c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTARE_FMSZE(x)             (((x) & 0x1) << 16)
+#define SPI_CTARE_DTCP(x)              ((x) & 0x7ff)
+
+#define SPI_SREX                       0x13c
+
+#define SPI_FRAME_BITS(bits)           SPI_CTAR_FMSZ((bits) - 1)
+#define SPI_FRAME_EBITS(bits)          SPI_CTARE_FMSZE(((bits) - 1) >> 4)
 
 /* Register offsets for regmap_pushr */
-#define PUSHR_CMD              0x0
-#define PUSHR_TX               0x2
+#define PUSHR_CMD                      0x0
+#define PUSHR_TX                       0x2
 
-#define SPI_CS_INIT            0x01
-#define SPI_CS_ASSERT          0x02
-#define SPI_CS_DROP            0x04
-
-#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
+#define DMA_COMPLETION_TIMEOUT         msecs_to_jiffies(3000)
 
 struct chip_data {
-       u32 ctar_val;
-       u16 void_write_data;
+       u32                     ctar_val;
+       u16                     void_write_data;
 };
 
 enum dspi_trans_mode {
@@ -141,75 +127,75 @@ enum dspi_trans_mode {
 };
 
 struct fsl_dspi_devtype_data {
-       enum dspi_trans_mode trans_mode;
-       u8 max_clock_factor;
-       bool xspi_mode;
+       enum dspi_trans_mode    trans_mode;
+       u8                      max_clock_factor;
+       bool                    xspi_mode;
 };
 
 static const struct fsl_dspi_devtype_data vf610_data = {
-       .trans_mode = DSPI_DMA_MODE,
-       .max_clock_factor = 2,
+       .trans_mode             = DSPI_DMA_MODE,
+       .max_clock_factor       = 2,
 };
 
 static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
-       .trans_mode = DSPI_TCFQ_MODE,
-       .max_clock_factor = 8,
-       .xspi_mode = true,
+       .trans_mode             = DSPI_TCFQ_MODE,
+       .max_clock_factor       = 8,
+       .xspi_mode              = true,
 };
 
 static const struct fsl_dspi_devtype_data ls2085a_data = {
-       .trans_mode = DSPI_TCFQ_MODE,
-       .max_clock_factor = 8,
+       .trans_mode             = DSPI_TCFQ_MODE,
+       .max_clock_factor       = 8,
 };
 
 static const struct fsl_dspi_devtype_data coldfire_data = {
-       .trans_mode = DSPI_EOQ_MODE,
-       .max_clock_factor = 8,
+       .trans_mode             = DSPI_EOQ_MODE,
+       .max_clock_factor       = 8,
 };
 
 struct fsl_dspi_dma {
        /* Length of transfer in words of DSPI_FIFO_SIZE */
-       u32 curr_xfer_len;
-
-       u32 *tx_dma_buf;
-       struct dma_chan *chan_tx;
-       dma_addr_t tx_dma_phys;
-       struct completion cmd_tx_complete;
-       struct dma_async_tx_descriptor *tx_desc;
-
-       u32 *rx_dma_buf;
-       struct dma_chan *chan_rx;
-       dma_addr_t rx_dma_phys;
-       struct completion cmd_rx_complete;
-       struct dma_async_tx_descriptor *rx_desc;
+       u32                                     curr_xfer_len;
+
+       u32                                     *tx_dma_buf;
+       struct dma_chan                         *chan_tx;
+       dma_addr_t                              tx_dma_phys;
+       struct completion                       cmd_tx_complete;
+       struct dma_async_tx_descriptor          *tx_desc;
+
+       u32                                     *rx_dma_buf;
+       struct dma_chan                         *chan_rx;
+       dma_addr_t                              rx_dma_phys;
+       struct completion                       cmd_rx_complete;
+       struct dma_async_tx_descriptor          *rx_desc;
 };
 
 struct fsl_dspi {
-       struct spi_master       *master;
-       struct platform_device  *pdev;
-
-       struct regmap           *regmap;
-       struct regmap           *regmap_pushr;
-       int                     irq;
-       struct clk              *clk;
-
-       struct spi_transfer     *cur_transfer;
-       struct spi_message      *cur_msg;
-       struct chip_data        *cur_chip;
-       size_t                  len;
-       const void              *tx;
-       void                    *rx;
-       void                    *rx_end;
-       u16                     void_write_data;
-       u16                     tx_cmd;
-       u8                      bits_per_word;
-       u8                      bytes_per_word;
-       const struct fsl_dspi_devtype_data *devtype_data;
-
-       wait_queue_head_t       waitq;
-       u32                     waitflags;
-
-       struct fsl_dspi_dma     *dma;
+       struct spi_controller                   *ctlr;
+       struct platform_device                  *pdev;
+
+       struct regmap                           *regmap;
+       struct regmap                           *regmap_pushr;
+       int                                     irq;
+       struct clk                              *clk;
+
+       struct spi_transfer                     *cur_transfer;
+       struct spi_message                      *cur_msg;
+       struct chip_data                        *cur_chip;
+       size_t                                  len;
+       const void                              *tx;
+       void                                    *rx;
+       void                                    *rx_end;
+       u16                                     void_write_data;
+       u16                                     tx_cmd;
+       u8                                      bits_per_word;
+       u8                                      bytes_per_word;
+       const struct fsl_dspi_devtype_data      *devtype_data;
+
+       wait_queue_head_t                       waitq;
+       u32                                     waitflags;
+
+       struct fsl_dspi_dma                     *dma;
 };
 
 static u32 dspi_pop_tx(struct fsl_dspi *dspi)
@@ -233,7 +219,7 @@ static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
 {
        u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
 
-       if (spi_controller_is_slave(dspi->master))
+       if (spi_controller_is_slave(dspi->ctlr))
                return data;
 
        if (dspi->len > 0)
@@ -246,7 +232,7 @@ static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
        if (!dspi->rx)
                return;
 
-       /* Mask of undefined bits */
+       /* Mask off undefined bits */
        rxdata &= (1 << dspi->bits_per_word) - 1;
 
        if (dspi->bytes_per_word == 1)
@@ -282,8 +268,8 @@ static void dspi_rx_dma_callback(void *arg)
 
 static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 {
-       struct fsl_dspi_dma *dma = dspi->dma;
        struct device *dev = &dspi->pdev->dev;
+       struct fsl_dspi_dma *dma = dspi->dma;
        int time_left;
        int i;
 
@@ -332,13 +318,13 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        dma_async_issue_pending(dma->chan_rx);
        dma_async_issue_pending(dma->chan_tx);
 
-       if (spi_controller_is_slave(dspi->master)) {
+       if (spi_controller_is_slave(dspi->ctlr)) {
                wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete);
                return 0;
        }
 
        time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete,
-                                       DMA_COMPLETION_TIMEOUT);
+                                               DMA_COMPLETION_TIMEOUT);
        if (time_left == 0) {
                dev_err(dev, "DMA tx timeout\n");
                dmaengine_terminate_all(dma->chan_tx);
@@ -347,7 +333,7 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        }
 
        time_left = wait_for_completion_timeout(&dspi->dma->cmd_rx_complete,
-                                       DMA_COMPLETION_TIMEOUT);
+                                               DMA_COMPLETION_TIMEOUT);
        if (time_left == 0) {
                dev_err(dev, "DMA rx timeout\n");
                dmaengine_terminate_all(dma->chan_tx);
@@ -360,9 +346,9 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
 static int dspi_dma_xfer(struct fsl_dspi *dspi)
 {
-       struct fsl_dspi_dma *dma = dspi->dma;
-       struct device *dev = &dspi->pdev->dev;
        struct spi_message *message = dspi->cur_msg;
+       struct device *dev = &dspi->pdev->dev;
+       struct fsl_dspi_dma *dma = dspi->dma;
        int curr_remaining_bytes;
        int bytes_per_buffer;
        int ret = 0;
@@ -397,9 +383,9 @@ exit:
 
 static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
 {
-       struct fsl_dspi_dma *dma;
-       struct dma_slave_config cfg;
        struct device *dev = &dspi->pdev->dev;
+       struct dma_slave_config cfg;
+       struct fsl_dspi_dma *dma;
        int ret;
 
        dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
@@ -421,14 +407,14 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
        }
 
        dma->tx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
-                                       &dma->tx_dma_phys, GFP_KERNEL);
+                                            &dma->tx_dma_phys, GFP_KERNEL);
        if (!dma->tx_dma_buf) {
                ret = -ENOMEM;
                goto err_tx_dma_buf;
        }
 
        dma->rx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
-                                       &dma->rx_dma_phys, GFP_KERNEL);
+                                            &dma->rx_dma_phys, GFP_KERNEL);
        if (!dma->rx_dma_buf) {
                ret = -ENOMEM;
                goto err_rx_dma_buf;
@@ -485,30 +471,31 @@ static void dspi_release_dma(struct fsl_dspi *dspi)
        struct fsl_dspi_dma *dma = dspi->dma;
        struct device *dev = &dspi->pdev->dev;
 
-       if (dma) {
-               if (dma->chan_tx) {
-                       dma_unmap_single(dev, dma->tx_dma_phys,
-                                       DSPI_DMA_BUFSIZE, DMA_TO_DEVICE);
-                       dma_release_channel(dma->chan_tx);
-               }
+       if (!dma)
+               return;
 
-               if (dma->chan_rx) {
-                       dma_unmap_single(dev, dma->rx_dma_phys,
-                                       DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE);
-                       dma_release_channel(dma->chan_rx);
-               }
+       if (dma->chan_tx) {
+               dma_unmap_single(dev, dma->tx_dma_phys,
+                                DSPI_DMA_BUFSIZE, DMA_TO_DEVICE);
+               dma_release_channel(dma->chan_tx);
+       }
+
+       if (dma->chan_rx) {
+               dma_unmap_single(dev, dma->rx_dma_phys,
+                                DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE);
+               dma_release_channel(dma->chan_rx);
        }
 }
 
 static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
-               unsigned long clkrate)
+                          unsigned long clkrate)
 {
        /* Valid baud rate pre-scaler values */
        int pbr_tbl[4] = {2, 3, 5, 7};
        int brs[16] = { 2,      4,      6,      8,
-               16,     32,     64,     128,
-               256,    512,    1024,   2048,
-               4096,   8192,   16384,  32768 };
+                       16,     32,     64,     128,
+                       256,    512,    1024,   2048,
+                       4096,   8192,   16384,  32768 };
        int scale_needed, scale, minscale = INT_MAX;
        int i, j;
 
@@ -538,15 +525,15 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
 }
 
 static void ns_delay_scale(char *psc, char *sc, int delay_ns,
-               unsigned long clkrate)
+                          unsigned long clkrate)
 {
-       int pscale_tbl[4] = {1, 3, 5, 7};
        int scale_needed, scale, minscale = INT_MAX;
-       int i, j;
+       int pscale_tbl[4] = {1, 3, 5, 7};
        u32 remainder;
+       int i, j;
 
        scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
-                       &remainder);
+                                  &remainder);
        if (remainder)
                scale_needed++;
 
@@ -601,7 +588,7 @@ static void dspi_tcfq_write(struct fsl_dspi *dspi)
                 */
                u32 data = dspi_pop_tx(dspi);
 
-               if (dspi->cur_chip->ctar_val & SPI_CTAR_LSBFE(1)) {
+               if (dspi->cur_chip->ctar_val & SPI_CTAR_LSBFE) {
                        /* LSB */
                        tx_fifo_write(dspi, data & 0xFFFF);
                        tx_fifo_write(dspi, data >> 16);
@@ -655,19 +642,90 @@ static void dspi_eoq_read(struct fsl_dspi *dspi)
 {
        int fifo_size = DSPI_FIFO_SIZE;
 
-       /* Read one FIFO entry at and push to rx buffer */
+       /* Read one FIFO entry and push to rx buffer */
        while ((dspi->rx < dspi->rx_end) && fifo_size--)
                dspi_push_rx(dspi, fifo_read(dspi));
 }
 
-static int dspi_transfer_one_message(struct spi_master *master,
-               struct spi_message *message)
+static int dspi_rxtx(struct fsl_dspi *dspi)
 {
-       struct fsl_dspi *dspi = spi_master_get_devdata(master);
+       struct spi_message *msg = dspi->cur_msg;
+       enum dspi_trans_mode trans_mode;
+       u16 spi_tcnt;
+       u32 spi_tcr;
+
+       /* Get transfer counter (in number of SPI transfers). It was
+        * reset to 0 when transfer(s) were started.
+        */
+       regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
+       spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
+       /* Update total number of bytes that were transferred */
+       msg->actual_length += spi_tcnt * dspi->bytes_per_word;
+
+       trans_mode = dspi->devtype_data->trans_mode;
+       if (trans_mode == DSPI_EOQ_MODE)
+               dspi_eoq_read(dspi);
+       else if (trans_mode == DSPI_TCFQ_MODE)
+               dspi_tcfq_read(dspi);
+
+       if (!dspi->len)
+               /* Success! */
+               return 0;
+
+       if (trans_mode == DSPI_EOQ_MODE)
+               dspi_eoq_write(dspi);
+       else if (trans_mode == DSPI_TCFQ_MODE)
+               dspi_tcfq_write(dspi);
+
+       return -EINPROGRESS;
+}
+
+static int dspi_poll(struct fsl_dspi *dspi)
+{
+       int tries = 1000;
+       u32 spi_sr;
+
+       do {
+               regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+               regmap_write(dspi->regmap, SPI_SR, spi_sr);
+
+               if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))
+                       break;
+       } while (--tries);
+
+       if (!tries)
+               return -ETIMEDOUT;
+
+       return dspi_rxtx(dspi);
+}
+
+static irqreturn_t dspi_interrupt(int irq, void *dev_id)
+{
+       struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
+       u32 spi_sr;
+
+       regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+       regmap_write(dspi->regmap, SPI_SR, spi_sr);
+
+       if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)))
+               return IRQ_NONE;
+
+       if (dspi_rxtx(dspi) == 0) {
+               dspi->waitflags = 1;
+               wake_up_interruptible(&dspi->waitq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int dspi_transfer_one_message(struct spi_controller *ctlr,
+                                    struct spi_message *message)
+{
+       struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
        struct spi_device *spi = message->spi;
+       enum dspi_trans_mode trans_mode;
        struct spi_transfer *transfer;
        int status = 0;
-       enum dspi_trans_mode trans_mode;
 
        message->actual_length = 0;
 
@@ -677,7 +735,7 @@ static int dspi_transfer_one_message(struct spi_master *master,
                dspi->cur_chip = spi_get_ctldata(spi);
                /* Prepare command word for CMD FIFO */
                dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
-                       SPI_PUSHR_CMD_PCS(spi->chip_select);
+                              SPI_PUSHR_CMD_PCS(spi->chip_select);
                if (list_is_last(&dspi->cur_transfer->transfer_list,
                                 &dspi->cur_msg->transfers)) {
                        /* Leave PCS activated after last transfer when
@@ -718,8 +776,8 @@ static int dspi_transfer_one_message(struct spi_master *master,
                             SPI_FRAME_BITS(transfer->bits_per_word));
                if (dspi->devtype_data->xspi_mode)
                        regmap_write(dspi->regmap, SPI_CTARE(0),
-                                    SPI_FRAME_EBITS(transfer->bits_per_word)
-                                    SPI_CTARE_DTCP(1));
+                                    SPI_FRAME_EBITS(transfer->bits_per_word) |
+                                    SPI_CTARE_DTCP(1));
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
@@ -733,8 +791,8 @@ static int dspi_transfer_one_message(struct spi_master *master,
                        break;
                case DSPI_DMA_MODE:
                        regmap_write(dspi->regmap, SPI_RSER,
-                               SPI_RSER_TFFFE | SPI_RSER_TFFFD |
-                               SPI_RSER_RFDFE | SPI_RSER_RFDFD);
+                                    SPI_RSER_TFFFE | SPI_RSER_TFFFD |
+                                    SPI_RSER_RFDFE | SPI_RSER_RFDFD);
                        status = dspi_dma_xfer(dspi);
                        break;
                default:
@@ -744,13 +802,18 @@ static int dspi_transfer_one_message(struct spi_master *master,
                        goto out;
                }
 
-               if (trans_mode != DSPI_DMA_MODE) {
-                       if (wait_event_interruptible(dspi->waitq,
-                                               dspi->waitflags))
-                               dev_err(&dspi->pdev->dev,
-                                       "wait transfer complete fail!\n");
+               if (!dspi->irq) {
+                       do {
+                               status = dspi_poll(dspi);
+                       } while (status == -EINPROGRESS);
+               } else if (trans_mode != DSPI_DMA_MODE) {
+                       status = wait_event_interruptible(dspi->waitq,
+                                                         dspi->waitflags);
                        dspi->waitflags = 0;
                }
+               if (status)
+                       dev_err(&dspi->pdev->dev,
+                               "Waiting for transfer to complete failed!\n");
 
                if (transfer->delay_usecs)
                        udelay(transfer->delay_usecs);
@@ -758,19 +821,19 @@ static int dspi_transfer_one_message(struct spi_master *master,
 
 out:
        message->status = status;
-       spi_finalize_current_message(master);
+       spi_finalize_current_message(ctlr);
 
        return status;
 }
 
 static int dspi_setup(struct spi_device *spi)
 {
-       struct chip_data *chip;
-       struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
-       struct fsl_dspi_platform_data *pdata;
-       u32 cs_sck_delay = 0, sck_cs_delay = 0;
+       struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller);
        unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
+       u32 cs_sck_delay = 0, sck_cs_delay = 0;
+       struct fsl_dspi_platform_data *pdata;
        unsigned char pasc = 0, asc = 0;
+       struct chip_data *chip;
        unsigned long clkrate;
 
        /* Only alloc on first setup */
@@ -785,10 +848,10 @@ static int dspi_setup(struct spi_device *spi)
 
        if (!pdata) {
                of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
-                               &cs_sck_delay);
+                                    &cs_sck_delay);
 
                of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
-                               &sck_cs_delay);
+                                    &sck_cs_delay);
        } else {
                cs_sck_delay = pdata->cs_sck_delay;
                sck_cs_delay = pdata->sck_cs_delay;
@@ -805,18 +868,22 @@ static int dspi_setup(struct spi_device *spi)
        /* Set After SCK delay scale values */
        ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
 
-       chip->ctar_val = SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
-               | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0);
-
-       if (!spi_controller_is_slave(dspi->master)) {
-               chip->ctar_val |= SPI_CTAR_LSBFE(spi->mode &
-                                                SPI_LSB_FIRST ? 1 : 0)
-                       | SPI_CTAR_PCSSCK(pcssck)
-                       | SPI_CTAR_CSSCK(cssck)
-                       | SPI_CTAR_PASC(pasc)
-                       | SPI_CTAR_ASC(asc)
-                       | SPI_CTAR_PBR(pbr)
-                       | SPI_CTAR_BR(br);
+       chip->ctar_val = 0;
+       if (spi->mode & SPI_CPOL)
+               chip->ctar_val |= SPI_CTAR_CPOL;
+       if (spi->mode & SPI_CPHA)
+               chip->ctar_val |= SPI_CTAR_CPHA;
+
+       if (!spi_controller_is_slave(dspi->ctlr)) {
+               chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) |
+                                 SPI_CTAR_CSSCK(cssck) |
+                                 SPI_CTAR_PASC(pasc) |
+                                 SPI_CTAR_ASC(asc) |
+                                 SPI_CTAR_PBR(pbr) |
+                                 SPI_CTAR_BR(br);
+
+               if (spi->mode & SPI_LSB_FIRST)
+                       chip->ctar_val |= SPI_CTAR_LSBFE;
        }
 
        spi_set_ctldata(spi, chip);
@@ -829,68 +896,11 @@ static void dspi_cleanup(struct spi_device *spi)
        struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
 
        dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n",
-                       spi->master->bus_num, spi->chip_select);
+               spi->controller->bus_num, spi->chip_select);
 
        kfree(chip);
 }
 
-static irqreturn_t dspi_interrupt(int irq, void *dev_id)
-{
-       struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
-       struct spi_message *msg = dspi->cur_msg;
-       enum dspi_trans_mode trans_mode;
-       u32 spi_sr, spi_tcr;
-       u16 spi_tcnt;
-
-       regmap_read(dspi->regmap, SPI_SR, &spi_sr);
-       regmap_write(dspi->regmap, SPI_SR, spi_sr);
-
-
-       if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
-               /* Get transfer counter (in number of SPI transfers). It was
-                * reset to 0 when transfer(s) were started.
-                */
-               regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
-               spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
-               /* Update total number of bytes that were transferred */
-               msg->actual_length += spi_tcnt * dspi->bytes_per_word;
-
-               trans_mode = dspi->devtype_data->trans_mode;
-               switch (trans_mode) {
-               case DSPI_EOQ_MODE:
-                       dspi_eoq_read(dspi);
-                       break;
-               case DSPI_TCFQ_MODE:
-                       dspi_tcfq_read(dspi);
-                       break;
-               default:
-                       dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
-                               trans_mode);
-                               return IRQ_HANDLED;
-               }
-
-               if (!dspi->len) {
-                       dspi->waitflags = 1;
-                       wake_up_interruptible(&dspi->waitq);
-               } else {
-                       switch (trans_mode) {
-                       case DSPI_EOQ_MODE:
-                               dspi_eoq_write(dspi);
-                               break;
-                       case DSPI_TCFQ_MODE:
-                               dspi_tcfq_write(dspi);
-                               break;
-                       default:
-                               dev_err(&dspi->pdev->dev,
-                                       "unsupported trans_mode %u\n",
-                                       trans_mode);
-                       }
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
 static const struct of_device_id fsl_dspi_dt_ids[] = {
        { .compatible = "fsl,vf610-dspi", .data = &vf610_data, },
        { .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, },
@@ -902,10 +912,10 @@ MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
 #ifdef CONFIG_PM_SLEEP
 static int dspi_suspend(struct device *dev)
 {
-       struct spi_master *master = dev_get_drvdata(dev);
-       struct fsl_dspi *dspi = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = dev_get_drvdata(dev);
+       struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
 
-       spi_master_suspend(master);
+       spi_controller_suspend(ctlr);
        clk_disable_unprepare(dspi->clk);
 
        pinctrl_pm_select_sleep_state(dev);
@@ -915,8 +925,8 @@ static int dspi_suspend(struct device *dev)
 
 static int dspi_resume(struct device *dev)
 {
-       struct spi_master *master = dev_get_drvdata(dev);
-       struct fsl_dspi *dspi = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = dev_get_drvdata(dev);
+       struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
        int ret;
 
        pinctrl_pm_select_default_state(dev);
@@ -924,7 +934,7 @@ static int dspi_resume(struct device *dev)
        ret = clk_prepare_enable(dspi->clk);
        if (ret)
                return ret;
-       spi_master_resume(master);
+       spi_controller_resume(ctlr);
 
        return 0;
 }
@@ -939,16 +949,16 @@ static const struct regmap_range dspi_volatile_ranges[] = {
 };
 
 static const struct regmap_access_table dspi_volatile_table = {
-       .yes_ranges     = dspi_volatile_ranges,
-       .n_yes_ranges   = ARRAY_SIZE(dspi_volatile_ranges),
+       .yes_ranges     = dspi_volatile_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(dspi_volatile_ranges),
 };
 
 static const struct regmap_config dspi_regmap_config = {
-       .reg_bits = 32,
-       .val_bits = 32,
-       .reg_stride = 4,
-       .max_register = 0x88,
-       .volatile_table = &dspi_volatile_table,
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = 0x88,
+       .volatile_table = &dspi_volatile_table,
 };
 
 static const struct regmap_range dspi_xspi_volatile_ranges[] = {
@@ -959,33 +969,34 @@ static const struct regmap_range dspi_xspi_volatile_ranges[] = {
 };
 
 static const struct regmap_access_table dspi_xspi_volatile_table = {
-       .yes_ranges     = dspi_xspi_volatile_ranges,
-       .n_yes_ranges   = ARRAY_SIZE(dspi_xspi_volatile_ranges),
+       .yes_ranges     = dspi_xspi_volatile_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(dspi_xspi_volatile_ranges),
 };
 
 static const struct regmap_config dspi_xspi_regmap_config[] = {
        {
-               .reg_bits = 32,
-               .val_bits = 32,
-               .reg_stride = 4,
-               .max_register = 0x13c,
-               .volatile_table = &dspi_xspi_volatile_table,
+               .reg_bits       = 32,
+               .val_bits       = 32,
+               .reg_stride     = 4,
+               .max_register   = 0x13c,
+               .volatile_table = &dspi_xspi_volatile_table,
        },
        {
-               .name = "pushr",
-               .reg_bits = 16,
-               .val_bits = 16,
-               .reg_stride = 2,
-               .max_register = 0x2,
+               .name           = "pushr",
+               .reg_bits       = 16,
+               .val_bits       = 16,
+               .reg_stride     = 2,
+               .max_register   = 0x2,
        },
 };
 
 static void dspi_init(struct fsl_dspi *dspi)
 {
-       unsigned int mcr = SPI_MCR_PCSIS |
-               (dspi->devtype_data->xspi_mode ? SPI_MCR_XSPI : 0);
+       unsigned int mcr = SPI_MCR_PCSIS;
 
-       if (!spi_controller_is_slave(dspi->master))
+       if (dspi->devtype_data->xspi_mode)
+               mcr |= SPI_MCR_XSPI;
+       if (!spi_controller_is_slave(dspi->ctlr))
                mcr |= SPI_MCR_MASTER;
 
        regmap_write(dspi->regmap, SPI_MCR, mcr);
@@ -998,34 +1009,33 @@ static void dspi_init(struct fsl_dspi *dspi)
 static int dspi_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct spi_master *master;
+       const struct regmap_config *regmap_config;
+       struct fsl_dspi_platform_data *pdata;
+       struct spi_controller *ctlr;
+       int ret, cs_num, bus_num;
        struct fsl_dspi *dspi;
        struct resource *res;
-       const struct regmap_config *regmap_config;
        void __iomem *base;
-       struct fsl_dspi_platform_data *pdata;
-       int ret = 0, cs_num, bus_num;
 
-       master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
-       if (!master)
+       ctlr = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
+       if (!ctlr)
                return -ENOMEM;
 
-       dspi = spi_master_get_devdata(master);
+       dspi = spi_controller_get_devdata(ctlr);
        dspi->pdev = pdev;
-       dspi->master = master;
+       dspi->ctlr = ctlr;
 
-       master->transfer = NULL;
-       master->setup = dspi_setup;
-       master->transfer_one_message = dspi_transfer_one_message;
-       master->dev.of_node = pdev->dev.of_node;
+       ctlr->setup = dspi_setup;
+       ctlr->transfer_one_message = dspi_transfer_one_message;
+       ctlr->dev.of_node = pdev->dev.of_node;
 
-       master->cleanup = dspi_cleanup;
-       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       ctlr->cleanup = dspi_cleanup;
+       ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
 
        pdata = dev_get_platdata(&pdev->dev);
        if (pdata) {
-               master->num_chipselect = pdata->cs_num;
-               master->bus_num = pdata->bus_num;
+               ctlr->num_chipselect = pdata->cs_num;
+               ctlr->bus_num = pdata->bus_num;
 
                dspi->devtype_data = &coldfire_data;
        } else {
@@ -1033,38 +1043,38 @@ static int dspi_probe(struct platform_device *pdev)
                ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
                if (ret < 0) {
                        dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
-                       goto out_master_put;
+                       goto out_ctlr_put;
                }
-               master->num_chipselect = cs_num;
+               ctlr->num_chipselect = cs_num;
 
                ret = of_property_read_u32(np, "bus-num", &bus_num);
                if (ret < 0) {
                        dev_err(&pdev->dev, "can't get bus-num\n");
-                       goto out_master_put;
+                       goto out_ctlr_put;
                }
-               master->bus_num = bus_num;
+               ctlr->bus_num = bus_num;
 
                if (of_property_read_bool(np, "spi-slave"))
-                       master->slave = true;
+                       ctlr->slave = true;
 
                dspi->devtype_data = of_device_get_match_data(&pdev->dev);
                if (!dspi->devtype_data) {
                        dev_err(&pdev->dev, "can't get devtype_data\n");
                        ret = -EFAULT;
-                       goto out_master_put;
+                       goto out_ctlr_put;
                }
        }
 
        if (dspi->devtype_data->xspi_mode)
-               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+               ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        else
-               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+               ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base)) {
                ret = PTR_ERR(base);
-               goto out_master_put;
+               goto out_ctlr_put;
        }
 
        if (dspi->devtype_data->xspi_mode)
@@ -1076,7 +1086,7 @@ static int dspi_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to init regmap: %ld\n",
                                PTR_ERR(dspi->regmap));
                ret = PTR_ERR(dspi->regmap);
-               goto out_master_put;
+               goto out_ctlr_put;
        }
 
        if (dspi->devtype_data->xspi_mode) {
@@ -1088,7 +1098,7 @@ static int dspi_probe(struct platform_device *pdev)
                                "failed to init pushr regmap: %ld\n",
                                PTR_ERR(dspi->regmap_pushr));
                        ret = PTR_ERR(dspi->regmap_pushr);
-                       goto out_master_put;
+                       goto out_ctlr_put;
                }
        }
 
@@ -1096,18 +1106,20 @@ static int dspi_probe(struct platform_device *pdev)
        if (IS_ERR(dspi->clk)) {
                ret = PTR_ERR(dspi->clk);
                dev_err(&pdev->dev, "unable to get clock\n");
-               goto out_master_put;
+               goto out_ctlr_put;
        }
        ret = clk_prepare_enable(dspi->clk);
        if (ret)
-               goto out_master_put;
+               goto out_ctlr_put;
 
        dspi_init(dspi);
+
        dspi->irq = platform_get_irq(pdev, 0);
-       if (dspi->irq < 0) {
-               dev_err(&pdev->dev, "can't get platform irq\n");
-               ret = dspi->irq;
-               goto out_clk_put;
+       if (dspi->irq <= 0) {
+               dev_info(&pdev->dev,
+                        "can't get platform irq, using poll mode\n");
+               dspi->irq = 0;
+               goto poll_mode;
        }
 
        ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt,
@@ -1117,6 +1129,9 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_clk_put;
        }
 
+       init_waitqueue_head(&dspi->waitq);
+
+poll_mode:
        if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
                ret = dspi_request_dma(dspi, res->start);
                if (ret < 0) {
@@ -1125,15 +1140,14 @@ static int dspi_probe(struct platform_device *pdev)
                }
        }
 
-       master->max_speed_hz =
+       ctlr->max_speed_hz =
                clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
 
-       init_waitqueue_head(&dspi->waitq);
-       platform_set_drvdata(pdev, master);
+       platform_set_drvdata(pdev, ctlr);
 
-       ret = spi_register_master(master);
+       ret = spi_register_controller(ctlr);
        if (ret != 0) {
-               dev_err(&pdev->dev, "Problem registering DSPI master\n");
+               dev_err(&pdev->dev, "Problem registering DSPI ctlr\n");
                goto out_clk_put;
        }
 
@@ -1141,32 +1155,32 @@ static int dspi_probe(struct platform_device *pdev)
 
 out_clk_put:
        clk_disable_unprepare(dspi->clk);
-out_master_put:
-       spi_master_put(master);
+out_ctlr_put:
+       spi_controller_put(ctlr);
 
        return ret;
 }
 
 static int dspi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
-       struct fsl_dspi *dspi = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = platform_get_drvdata(pdev);
+       struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
 
        /* Disconnect from the SPI framework */
        dspi_release_dma(dspi);
        clk_disable_unprepare(dspi->clk);
-       spi_unregister_master(dspi->master);
+       spi_unregister_controller(dspi->ctlr);
 
        return 0;
 }
 
 static struct platform_driver fsl_dspi_driver = {
-       .driver.name    = DRIVER_NAME,
-       .driver.of_match_table = fsl_dspi_dt_ids,
-       .driver.owner   = THIS_MODULE,
-       .driver.pm = &dspi_pm,
-       .probe          = dspi_probe,
-       .remove         = dspi_remove,
+       .driver.name            = DRIVER_NAME,
+       .driver.of_match_table  = fsl_dspi_dt_ids,
+       .driver.owner           = THIS_MODULE,
+       .driver.pm              = &dspi_pm,
+       .probe                  = dspi_probe,
+       .remove                 = dspi_remove,
 };
 module_platform_driver(fsl_dspi_driver);
 
index 3576167..015a1ab 100644 (file)
@@ -91,9 +91,6 @@ static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
 
 struct mpc8xxx_spi_probe_info {
        struct fsl_spi_platform_data pdata;
-       int ngpios;
-       int *gpios;
-       bool *alow_flags;
        __be32 __iomem *immr_spi_cs;
 };
 
index 448c00e..c02e24c 100644 (file)
@@ -860,10 +860,8 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 
        /* find the irq */
        ret = platform_get_irq(pdev, 0);
-       if (ret < 0) {
-               dev_err(dev, "failed to get the irq: %d\n", ret);
+       if (ret < 0)
                goto err_disable_clk;
-       }
 
        ret = devm_request_irq(dev, ret,
                        fsl_qspi_irq_handler, 0, pdev->name, q);
index 1d9b33a..4b80ace 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/fsl_devices.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
@@ -28,7 +28,6 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
@@ -481,32 +480,6 @@ static int fsl_spi_setup(struct spi_device *spi)
                return retval;
        }
 
-       if (mpc8xxx_spi->type == TYPE_GRLIB) {
-               if (gpio_is_valid(spi->cs_gpio)) {
-                       int desel;
-
-                       retval = gpio_request(spi->cs_gpio,
-                                             dev_name(&spi->dev));
-                       if (retval)
-                               return retval;
-
-                       desel = !(spi->mode & SPI_CS_HIGH);
-                       retval = gpio_direction_output(spi->cs_gpio, desel);
-                       if (retval) {
-                               gpio_free(spi->cs_gpio);
-                               return retval;
-                       }
-               } else if (spi->cs_gpio != -ENOENT) {
-                       if (spi->cs_gpio < 0)
-                               return spi->cs_gpio;
-                       return -EINVAL;
-               }
-               /* When spi->cs_gpio == -ENOENT, a hole in the phandle list
-                * indicates to use native chipselect if present, or allow for
-                * an always selected chip
-                */
-       }
-
        /* Initialize chipselect - might be active for SPI_CS_HIGH mode */
        fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
 
@@ -515,12 +488,8 @@ static int fsl_spi_setup(struct spi_device *spi)
 
 static void fsl_spi_cleanup(struct spi_device *spi)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
        struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
 
-       if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio))
-               gpio_free(spi->cs_gpio);
-
        kfree(cs);
        spi_set_ctldata(spi, NULL);
 }
@@ -586,8 +555,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
        u32 slvsel;
        u16 cs = spi->chip_select;
 
-       if (gpio_is_valid(spi->cs_gpio)) {
-               gpio_set_value(spi->cs_gpio, on);
+       if (spi->cs_gpiod) {
+               gpiod_set_value(spi->cs_gpiod, on);
        } else if (cs < mpc8xxx_spi->native_chipselects) {
                slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel);
                slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs));
@@ -718,139 +687,19 @@ err:
 
 static void fsl_spi_cs_control(struct spi_device *spi, bool on)
 {
-       struct device *dev = spi->dev.parent->parent;
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
-       struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-       u16 cs = spi->chip_select;
-
-       if (cs < pinfo->ngpios) {
-               int gpio = pinfo->gpios[cs];
-               bool alow = pinfo->alow_flags[cs];
-
-               gpio_set_value(gpio, on ^ alow);
+       if (spi->cs_gpiod) {
+               gpiod_set_value(spi->cs_gpiod, on);
        } else {
-               if (WARN_ON_ONCE(cs > pinfo->ngpios || !pinfo->immr_spi_cs))
+               struct device *dev = spi->dev.parent->parent;
+               struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+               struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+
+               if (WARN_ON_ONCE(!pinfo->immr_spi_cs))
                        return;
                iowrite32be(on ? SPI_BOOT_SEL_BIT : 0, pinfo->immr_spi_cs);
        }
 }
 
-static int of_fsl_spi_get_chipselects(struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
-       struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-       bool spisel_boot = IS_ENABLED(CONFIG_FSL_SOC) &&
-               of_property_read_bool(np, "fsl,spisel_boot");
-       int ngpios;
-       int i = 0;
-       int ret;
-
-       ngpios = of_gpio_count(np);
-       ngpios = max(ngpios, 0);
-       if (ngpios == 0 && !spisel_boot) {
-               /*
-                * SPI w/o chip-select line. One SPI device is still permitted
-                * though.
-                */
-               pdata->max_chipselect = 1;
-               return 0;
-       }
-
-       pinfo->ngpios = ngpios;
-       pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios),
-                                    GFP_KERNEL);
-       if (!pinfo->gpios)
-               return -ENOMEM;
-       memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
-
-       pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags),
-                                   GFP_KERNEL);
-       if (!pinfo->alow_flags) {
-               ret = -ENOMEM;
-               goto err_alloc_flags;
-       }
-
-       for (; i < ngpios; i++) {
-               int gpio;
-               enum of_gpio_flags flags;
-
-               gpio = of_get_gpio_flags(np, i, &flags);
-               if (!gpio_is_valid(gpio)) {
-                       dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
-                       ret = gpio;
-                       goto err_loop;
-               }
-
-               ret = gpio_request(gpio, dev_name(dev));
-               if (ret) {
-                       dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
-                       goto err_loop;
-               }
-
-               pinfo->gpios[i] = gpio;
-               pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
-
-               ret = gpio_direction_output(pinfo->gpios[i],
-                                           pinfo->alow_flags[i]);
-               if (ret) {
-                       dev_err(dev,
-                               "can't set output direction for gpio #%d: %d\n",
-                               i, ret);
-                       goto err_loop;
-               }
-       }
-
-#if IS_ENABLED(CONFIG_FSL_SOC)
-       if (spisel_boot) {
-               pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4);
-               if (!pinfo->immr_spi_cs) {
-                       ret = -ENOMEM;
-                       i = ngpios - 1;
-                       goto err_loop;
-               }
-       }
-#endif
-
-       pdata->max_chipselect = ngpios + spisel_boot;
-       pdata->cs_control = fsl_spi_cs_control;
-
-       return 0;
-
-err_loop:
-       while (i >= 0) {
-               if (gpio_is_valid(pinfo->gpios[i]))
-                       gpio_free(pinfo->gpios[i]);
-               i--;
-       }
-
-       kfree(pinfo->alow_flags);
-       pinfo->alow_flags = NULL;
-err_alloc_flags:
-       kfree(pinfo->gpios);
-       pinfo->gpios = NULL;
-       return ret;
-}
-
-static int of_fsl_spi_free_chipselects(struct device *dev)
-{
-       struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
-       struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-       int i;
-
-       if (!pinfo->gpios)
-               return 0;
-
-       for (i = 0; i < pdata->max_chipselect; i++) {
-               if (gpio_is_valid(pinfo->gpios[i]))
-                       gpio_free(pinfo->gpios[i]);
-       }
-
-       kfree(pinfo->gpios);
-       kfree(pinfo->alow_flags);
-       return 0;
-}
-
 static int of_fsl_spi_probe(struct platform_device *ofdev)
 {
        struct device *dev = &ofdev->dev;
@@ -866,9 +715,21 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
 
        type = fsl_spi_get_type(&ofdev->dev);
        if (type == TYPE_FSL) {
-               ret = of_fsl_spi_get_chipselects(dev);
-               if (ret)
-                       goto err;
+               struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+#if IS_ENABLED(CONFIG_FSL_SOC)
+               struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+               bool spisel_boot = of_property_read_bool(np, "fsl,spisel_boot");
+
+               if (spisel_boot) {
+                       pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4);
+                       if (!pinfo->immr_spi_cs) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+               }
+#endif
+
+               pdata->cs_control = fsl_spi_cs_control;
        }
 
        ret = of_address_to_resource(np, 0, &mem);
@@ -891,8 +752,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
 
 err:
        irq_dispose_mapping(irq);
-       if (type == TYPE_FSL)
-               of_fsl_spi_free_chipselects(dev);
        return ret;
 }
 
@@ -902,8 +761,6 @@ static int of_fsl_spi_remove(struct platform_device *ofdev)
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
 
        fsl_spi_cpm_free(mpc8xxx_spi);
-       if (mpc8xxx_spi->type == TYPE_FSL)
-               of_fsl_spi_free_chipselects(&ofdev->dev);
        return 0;
 }
 
index 5f0b0d5..6f3d64a 100644 (file)
@@ -534,18 +534,14 @@ static int spi_geni_probe(struct platform_device *pdev)
        int ret, irq;
        struct spi_master *spi;
        struct spi_geni_master *mas;
-       struct resource *res;
        void __iomem *base;
        struct clk *clk;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "Err getting IRQ %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index 9eb8215..1d3e23e 100644 (file)
@@ -290,10 +290,7 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio)
                return PTR_ERR(spi_gpio->miso);
 
        spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
-       if (IS_ERR(spi_gpio->sck))
-               return PTR_ERR(spi_gpio->sck);
-
-       return 0;
+       return PTR_ERR_OR_ZERO(spi_gpio->sck);
 }
 
 #ifdef CONFIG_OF
index 8f01858..9dfe8b0 100644 (file)
@@ -819,22 +819,16 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
        }
 
        rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
-       if (rx_irq < 0) {
-               dev_err(dev, "failed to get %s\n", LTQ_SPI_RX_IRQ_NAME);
+       if (rx_irq < 0)
                return -ENXIO;
-       }
 
        tx_irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
-       if (tx_irq < 0) {
-               dev_err(dev, "failed to get %s\n", LTQ_SPI_TX_IRQ_NAME);
+       if (tx_irq < 0)
                return -ENXIO;
-       }
 
        err_irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
-       if (err_irq < 0) {
-               dev_err(dev, "failed to get %s\n", LTQ_SPI_ERR_IRQ_NAME);
+       if (err_irq < 0)
                return -ENXIO;
-       }
 
        master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi));
        if (!master)
index f50779f..2d43654 100644 (file)
@@ -185,7 +185,6 @@ spi_lp8841_rtc_probe(struct platform_device *pdev)
        int                             ret;
        struct spi_master               *master;
        struct spi_lp8841_rtc           *data;
-       void                            *iomem;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*data));
        if (!master)
@@ -207,8 +206,7 @@ spi_lp8841_rtc_probe(struct platform_device *pdev)
 
        data = spi_master_get_devdata(master);
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->iomem = devm_ioremap_resource(&pdev->dev, iomem);
+       data->iomem = devm_platform_ioremap_resource(pdev, 0);
        ret = PTR_ERR_OR_ZERO(data->iomem);
        if (ret) {
                dev_err(&pdev->dev, "failed to get IO address\n");
index 7fe4488..f3f1044 100644 (file)
@@ -503,7 +503,6 @@ static int meson_spicc_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct meson_spicc_device *spicc;
-       struct resource *res;
        int ret, irq, rate;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*spicc));
@@ -517,8 +516,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
        spicc->pdev = pdev;
        platform_set_drvdata(pdev, spicc);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spicc->base = devm_ioremap_resource(&pdev->dev, res);
+       spicc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spicc->base)) {
                dev_err(&pdev->dev, "io resource mapping failed\n");
                ret = PTR_ERR(spicc->base);
index f7fe9b1..c7b0399 100644 (file)
@@ -286,7 +286,6 @@ static int meson_spifc_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct meson_spifc *spifc;
-       struct resource *res;
        void __iomem *base;
        unsigned int rate;
        int ret = 0;
@@ -300,8 +299,7 @@ static int meson_spifc_probe(struct platform_device *pdev)
        spifc = spi_master_get_devdata(master);
        spifc->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(spifc->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base)) {
                ret = PTR_ERR(base);
                goto out_err;
index 45d8a70..6888a4d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_data/spi-mt65xx.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
 
 #define SPI_CFG0_REG                      0x0000
 #define SPI_CFG1_REG                      0x0004
@@ -28,6 +29,8 @@
 #define SPI_STATUS0_REG                   0x001c
 #define SPI_PAD_SEL_REG                   0x0024
 #define SPI_CFG2_REG                      0x0028
+#define SPI_TX_SRC_REG_64                 0x002c
+#define SPI_RX_DST_REG_64                 0x0030
 
 #define SPI_CFG0_SCK_HIGH_OFFSET          0
 #define SPI_CFG0_SCK_LOW_OFFSET           8
 
 #define MTK_SPI_MAX_FIFO_SIZE 32U
 #define MTK_SPI_PACKET_SIZE 1024
+#define MTK_SPI_32BITS_MASK  (0xffffffff)
+
+#define DMA_ADDR_EXT_BITS (36)
+#define DMA_ADDR_DEF_BITS (32)
 
 struct mtk_spi_compatible {
        bool need_pad_sel;
@@ -80,6 +87,8 @@ struct mtk_spi_compatible {
        bool must_tx;
        /* some IC design adjust cfg register to enhance time accuracy */
        bool enhance_timing;
+       /* some IC support DMA addr extension */
+       bool dma_ext;
 };
 
 struct mtk_spi {
@@ -102,6 +111,13 @@ static const struct mtk_spi_compatible mt2712_compat = {
        .must_tx = true,
 };
 
+static const struct mtk_spi_compatible mt6765_compat = {
+       .need_pad_sel = true,
+       .must_tx = true,
+       .enhance_timing = true,
+       .dma_ext = true,
+};
+
 static const struct mtk_spi_compatible mt7622_compat = {
        .must_tx = true,
        .enhance_timing = true,
@@ -137,6 +153,9 @@ static const struct of_device_id mtk_spi_of_match[] = {
        { .compatible = "mediatek,mt6589-spi",
                .data = (void *)&mtk_common_compat,
        },
+       { .compatible = "mediatek,mt6765-spi",
+               .data = (void *)&mt6765_compat,
+       },
        { .compatible = "mediatek,mt7622-spi",
                .data = (void *)&mt7622_compat,
        },
@@ -371,10 +390,25 @@ static void mtk_spi_setup_dma_addr(struct spi_master *master,
 {
        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);
+       if (mdata->tx_sgl) {
+               writel((u32)(xfer->tx_dma & MTK_SPI_32BITS_MASK),
+                      mdata->base + SPI_TX_SRC_REG);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+               if (mdata->dev_comp->dma_ext)
+                       writel((u32)(xfer->tx_dma >> 32),
+                              mdata->base + SPI_TX_SRC_REG_64);
+#endif
+       }
+
+       if (mdata->rx_sgl) {
+               writel((u32)(xfer->rx_dma & MTK_SPI_32BITS_MASK),
+                      mdata->base + SPI_RX_DST_REG);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+               if (mdata->dev_comp->dma_ext)
+                       writel((u32)(xfer->rx_dma >> 32),
+                              mdata->base + SPI_RX_DST_REG_64);
+#endif
+       }
 }
 
 static int mtk_spi_fifo_transfer(struct spi_master *master,
@@ -586,7 +620,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
        struct mtk_spi *mdata;
        const struct of_device_id *of_id;
        struct resource *res;
-       int i, irq, ret;
+       int i, irq, ret, addr_bits;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
        if (!master) {
@@ -664,7 +698,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
 
        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;
        }
@@ -753,6 +786,15 @@ static int mtk_spi_probe(struct platform_device *pdev)
                }
        }
 
+       if (mdata->dev_comp->dma_ext)
+               addr_bits = DMA_ADDR_EXT_BITS;
+       else
+               addr_bits = DMA_ADDR_DEF_BITS;
+       ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(addr_bits));
+       if (ret)
+               dev_notice(&pdev->dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
+                          addr_bits, ret);
+
        return 0;
 
 err_disable_runtime_pm:
index ff85982..2c3b7a2 100644 (file)
@@ -327,7 +327,6 @@ static int mt7621_spi_probe(struct platform_device *pdev)
        struct spi_controller *master;
        struct mt7621_spi *rs;
        void __iomem *base;
-       struct resource *r;
        int status = 0;
        struct clk *clk;
        int ret;
@@ -336,8 +335,7 @@ static int mt7621_spi_probe(struct platform_device *pdev)
        if (!match)
                return -EINVAL;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, r);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index 7bf53cf..996c1c8 100644 (file)
@@ -532,7 +532,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct mxs_spi *spi;
        struct mxs_ssp *ssp;
-       struct resource *iores;
        struct clk *clk;
        void __iomem *base;
        int devid, clk_freq;
@@ -545,12 +544,11 @@ static int mxs_spi_probe(struct platform_device *pdev)
         */
        const int clk_freq_default = 160000000;
 
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq_err = platform_get_irq(pdev, 0);
        if (irq_err < 0)
                return irq_err;
 
-       base = devm_ioremap_resource(&pdev->dev, iores);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c
new file mode 100644 (file)
index 0000000..cb52fd8
--- /dev/null
@@ -0,0 +1,769 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Nuvoton Technology corporation.
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/mfd/syscon.h>
+
+/* NPCM7xx GCR module */
+#define NPCM7XX_INTCR3_OFFSET          0x9C
+#define NPCM7XX_INTCR3_FIU_FIX         BIT(6)
+
+/* Flash Interface Unit (FIU) Registers */
+#define NPCM_FIU_DRD_CFG               0x00
+#define NPCM_FIU_DWR_CFG               0x04
+#define NPCM_FIU_UMA_CFG               0x08
+#define NPCM_FIU_UMA_CTS               0x0C
+#define NPCM_FIU_UMA_CMD               0x10
+#define NPCM_FIU_UMA_ADDR              0x14
+#define NPCM_FIU_PRT_CFG               0x18
+#define NPCM_FIU_UMA_DW0               0x20
+#define NPCM_FIU_UMA_DW1               0x24
+#define NPCM_FIU_UMA_DW2               0x28
+#define NPCM_FIU_UMA_DW3               0x2C
+#define NPCM_FIU_UMA_DR0               0x30
+#define NPCM_FIU_UMA_DR1               0x34
+#define NPCM_FIU_UMA_DR2               0x38
+#define NPCM_FIU_UMA_DR3               0x3C
+#define NPCM_FIU_MAX_REG_LIMIT         0x80
+
+/* FIU Direct Read Configuration Register */
+#define NPCM_FIU_DRD_CFG_LCK           BIT(31)
+#define NPCM_FIU_DRD_CFG_R_BURST       GENMASK(25, 24)
+#define NPCM_FIU_DRD_CFG_ADDSIZ                GENMASK(17, 16)
+#define NPCM_FIU_DRD_CFG_DBW           GENMASK(13, 12)
+#define NPCM_FIU_DRD_CFG_ACCTYPE       GENMASK(9, 8)
+#define NPCM_FIU_DRD_CFG_RDCMD         GENMASK(7, 0)
+#define NPCM_FIU_DRD_ADDSIZ_SHIFT      16
+#define NPCM_FIU_DRD_DBW_SHIFT         12
+#define NPCM_FIU_DRD_ACCTYPE_SHIFT     8
+
+/* FIU Direct Write Configuration Register */
+#define NPCM_FIU_DWR_CFG_LCK           BIT(31)
+#define NPCM_FIU_DWR_CFG_W_BURST       GENMASK(25, 24)
+#define NPCM_FIU_DWR_CFG_ADDSIZ                GENMASK(17, 16)
+#define NPCM_FIU_DWR_CFG_ABPCK         GENMASK(11, 10)
+#define NPCM_FIU_DWR_CFG_DBPCK         GENMASK(9, 8)
+#define NPCM_FIU_DWR_CFG_WRCMD         GENMASK(7, 0)
+#define NPCM_FIU_DWR_ADDSIZ_SHIFT      16
+#define NPCM_FIU_DWR_ABPCK_SHIFT       10
+#define NPCM_FIU_DWR_DBPCK_SHIFT       8
+
+/* FIU UMA Configuration Register */
+#define NPCM_FIU_UMA_CFG_LCK           BIT(31)
+#define NPCM_FIU_UMA_CFG_CMMLCK                BIT(30)
+#define NPCM_FIU_UMA_CFG_RDATSIZ       GENMASK(28, 24)
+#define NPCM_FIU_UMA_CFG_DBSIZ         GENMASK(23, 21)
+#define NPCM_FIU_UMA_CFG_WDATSIZ       GENMASK(20, 16)
+#define NPCM_FIU_UMA_CFG_ADDSIZ                GENMASK(13, 11)
+#define NPCM_FIU_UMA_CFG_CMDSIZ                BIT(10)
+#define NPCM_FIU_UMA_CFG_RDBPCK                GENMASK(9, 8)
+#define NPCM_FIU_UMA_CFG_DBPCK         GENMASK(7, 6)
+#define NPCM_FIU_UMA_CFG_WDBPCK                GENMASK(5, 4)
+#define NPCM_FIU_UMA_CFG_ADBPCK                GENMASK(3, 2)
+#define NPCM_FIU_UMA_CFG_CMBPCK                GENMASK(1, 0)
+#define NPCM_FIU_UMA_CFG_ADBPCK_SHIFT  2
+#define NPCM_FIU_UMA_CFG_WDBPCK_SHIFT  4
+#define NPCM_FIU_UMA_CFG_DBPCK_SHIFT   6
+#define NPCM_FIU_UMA_CFG_RDBPCK_SHIFT  8
+#define NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT  11
+#define NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT 16
+#define NPCM_FIU_UMA_CFG_DBSIZ_SHIFT   21
+#define NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT 24
+
+/* FIU UMA Control and Status Register */
+#define NPCM_FIU_UMA_CTS_RDYIE         BIT(25)
+#define NPCM_FIU_UMA_CTS_RDYST         BIT(24)
+#define NPCM_FIU_UMA_CTS_SW_CS         BIT(16)
+#define NPCM_FIU_UMA_CTS_DEV_NUM       GENMASK(9, 8)
+#define NPCM_FIU_UMA_CTS_EXEC_DONE     BIT(0)
+#define NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT 8
+
+/* FIU UMA Command Register */
+#define NPCM_FIU_UMA_CMD_DUM3          GENMASK(31, 24)
+#define NPCM_FIU_UMA_CMD_DUM2          GENMASK(23, 16)
+#define NPCM_FIU_UMA_CMD_DUM1          GENMASK(15, 8)
+#define NPCM_FIU_UMA_CMD_CMD           GENMASK(7, 0)
+
+/* FIU UMA Address Register */
+#define NPCM_FIU_UMA_ADDR_UMA_ADDR     GENMASK(31, 0)
+#define NPCM_FIU_UMA_ADDR_AB3          GENMASK(31, 24)
+#define NPCM_FIU_UMA_ADDR_AB2          GENMASK(23, 16)
+#define NPCM_FIU_UMA_ADDR_AB1          GENMASK(15, 8)
+#define NPCM_FIU_UMA_ADDR_AB0          GENMASK(7, 0)
+
+/* FIU UMA Write Data Bytes 0-3 Register */
+#define NPCM_FIU_UMA_DW0_WB3           GENMASK(31, 24)
+#define NPCM_FIU_UMA_DW0_WB2           GENMASK(23, 16)
+#define NPCM_FIU_UMA_DW0_WB1           GENMASK(15, 8)
+#define NPCM_FIU_UMA_DW0_WB0           GENMASK(7, 0)
+
+/* FIU UMA Write Data Bytes 4-7 Register */
+#define NPCM_FIU_UMA_DW1_WB7           GENMASK(31, 24)
+#define NPCM_FIU_UMA_DW1_WB6           GENMASK(23, 16)
+#define NPCM_FIU_UMA_DW1_WB5           GENMASK(15, 8)
+#define NPCM_FIU_UMA_DW1_WB4           GENMASK(7, 0)
+
+/* FIU UMA Write Data Bytes 8-11 Register */
+#define NPCM_FIU_UMA_DW2_WB11          GENMASK(31, 24)
+#define NPCM_FIU_UMA_DW2_WB10          GENMASK(23, 16)
+#define NPCM_FIU_UMA_DW2_WB9           GENMASK(15, 8)
+#define NPCM_FIU_UMA_DW2_WB8           GENMASK(7, 0)
+
+/* FIU UMA Write Data Bytes 12-15 Register */
+#define NPCM_FIU_UMA_DW3_WB15          GENMASK(31, 24)
+#define NPCM_FIU_UMA_DW3_WB14          GENMASK(23, 16)
+#define NPCM_FIU_UMA_DW3_WB13          GENMASK(15, 8)
+#define NPCM_FIU_UMA_DW3_WB12          GENMASK(7, 0)
+
+/* FIU UMA Read Data Bytes 0-3 Register */
+#define NPCM_FIU_UMA_DR0_RB3           GENMASK(31, 24)
+#define NPCM_FIU_UMA_DR0_RB2           GENMASK(23, 16)
+#define NPCM_FIU_UMA_DR0_RB1           GENMASK(15, 8)
+#define NPCM_FIU_UMA_DR0_RB0           GENMASK(7, 0)
+
+/* FIU UMA Read Data Bytes 4-7 Register */
+#define NPCM_FIU_UMA_DR1_RB15          GENMASK(31, 24)
+#define NPCM_FIU_UMA_DR1_RB14          GENMASK(23, 16)
+#define NPCM_FIU_UMA_DR1_RB13          GENMASK(15, 8)
+#define NPCM_FIU_UMA_DR1_RB12          GENMASK(7, 0)
+
+/* FIU UMA Read Data Bytes 8-11 Register */
+#define NPCM_FIU_UMA_DR2_RB15          GENMASK(31, 24)
+#define NPCM_FIU_UMA_DR2_RB14          GENMASK(23, 16)
+#define NPCM_FIU_UMA_DR2_RB13          GENMASK(15, 8)
+#define NPCM_FIU_UMA_DR2_RB12          GENMASK(7, 0)
+
+/* FIU UMA Read Data Bytes 12-15 Register */
+#define NPCM_FIU_UMA_DR3_RB15          GENMASK(31, 24)
+#define NPCM_FIU_UMA_DR3_RB14          GENMASK(23, 16)
+#define NPCM_FIU_UMA_DR3_RB13          GENMASK(15, 8)
+#define NPCM_FIU_UMA_DR3_RB12          GENMASK(7, 0)
+
+/* FIU Read Mode */
+enum {
+       DRD_SINGLE_WIRE_MODE    = 0,
+       DRD_DUAL_IO_MODE        = 1,
+       DRD_QUAD_IO_MODE        = 2,
+       DRD_SPI_X_MODE          = 3,
+};
+
+enum {
+       DWR_ABPCK_BIT_PER_CLK   = 0,
+       DWR_ABPCK_2_BIT_PER_CLK = 1,
+       DWR_ABPCK_4_BIT_PER_CLK = 2,
+};
+
+enum {
+       DWR_DBPCK_BIT_PER_CLK   = 0,
+       DWR_DBPCK_2_BIT_PER_CLK = 1,
+       DWR_DBPCK_4_BIT_PER_CLK = 2,
+};
+
+#define NPCM_FIU_DRD_16_BYTE_BURST     0x3000000
+#define NPCM_FIU_DWR_16_BYTE_BURST     0x3000000
+
+#define MAP_SIZE_128MB                 0x8000000
+#define MAP_SIZE_16MB                  0x1000000
+#define MAP_SIZE_8MB                   0x800000
+
+#define NUM_BITS_IN_BYTE               8
+#define FIU_DRD_MAX_DUMMY_NUMBER       3
+#define NPCM_MAX_CHIP_NUM              4
+#define CHUNK_SIZE                     16
+#define UMA_MICRO_SEC_TIMEOUT          150
+
+enum {
+       FIU0 = 0,
+       FIU3,
+       FIUX,
+};
+
+struct npcm_fiu_info {
+       char *name;
+       u32 fiu_id;
+       u32 max_map_size;
+       u32 max_cs;
+};
+
+struct fiu_data {
+       const struct npcm_fiu_info *npcm_fiu_data_info;
+       int fiu_max;
+};
+
+static const struct npcm_fiu_info npxm7xx_fiu_info[] = {
+       {.name = "FIU0", .fiu_id = FIU0,
+               .max_map_size = MAP_SIZE_128MB, .max_cs = 2},
+       {.name = "FIU3", .fiu_id = FIU3,
+               .max_map_size = MAP_SIZE_128MB, .max_cs = 4},
+       {.name = "FIUX", .fiu_id = FIUX,
+               .max_map_size = MAP_SIZE_16MB, .max_cs = 2} };
+
+static const struct fiu_data npxm7xx_fiu_data = {
+       .npcm_fiu_data_info = npxm7xx_fiu_info,
+       .fiu_max = 3,
+};
+
+struct npcm_fiu_spi;
+
+struct npcm_fiu_chip {
+       void __iomem *flash_region_mapped_ptr;
+       struct npcm_fiu_spi *fiu;
+       unsigned long clkrate;
+       u32 chipselect;
+};
+
+struct npcm_fiu_spi {
+       struct npcm_fiu_chip chip[NPCM_MAX_CHIP_NUM];
+       const struct npcm_fiu_info *info;
+       struct spi_mem_op drd_op;
+       struct resource *res_mem;
+       struct regmap *regmap;
+       unsigned long clkrate;
+       struct device *dev;
+       struct clk *clk;
+       bool spix_mode;
+};
+
+static const struct regmap_config npcm_mtd_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = NPCM_FIU_MAX_REG_LIMIT,
+};
+
+static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
+                            const struct spi_mem_op *op)
+{
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_ACCTYPE,
+                          ilog2(op->addr.buswidth) <<
+                          NPCM_FIU_DRD_ACCTYPE_SHIFT);
+       fiu->drd_op.addr.buswidth = op->addr.buswidth;
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_DBW,
+                          ((op->dummy.nbytes * ilog2(op->addr.buswidth))
+                           / NUM_BITS_IN_BYTE) << NPCM_FIU_DRD_DBW_SHIFT);
+       fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
+       fiu->drd_op.cmd.opcode = op->cmd.opcode;
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_ADDSIZ,
+                          (op->addr.nbytes - 3) << NPCM_FIU_DRD_ADDSIZ_SHIFT);
+       fiu->drd_op.addr.nbytes = op->addr.nbytes;
+}
+
+static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
+                                   u64 offs, size_t len, void *buf)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(desc->mem->spi->master);
+       struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
+       void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
+                                            offs);
+       u8 *buf_rx = buf;
+       u32 i;
+
+       if (fiu->spix_mode) {
+               for (i = 0 ; i < len ; i++)
+                       *(buf_rx + i) = ioread8(src + i);
+       } else {
+               if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth ||
+                   desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes ||
+                   desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode ||
+                   desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes)
+                       npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
+
+               memcpy_fromio(buf_rx, src, len);
+       }
+
+       return len;
+}
+
+static ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
+                                    u64 offs, size_t len, const void *buf)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(desc->mem->spi->master);
+       struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
+       void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
+                                            offs);
+       const u8 *buf_tx = buf;
+       u32 i;
+
+       if (fiu->spix_mode)
+               for (i = 0 ; i < len ; i++)
+                       iowrite8(*(buf_tx + i), dst + i);
+       else
+               memcpy_toio(dst, buf_tx, len);
+
+       return len;
+}
+
+static int npcm_fiu_uma_read(struct spi_mem *mem,
+                            const struct spi_mem_op *op, u32 addr,
+                             bool is_address_size, u8 *data, u32 data_size)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(mem->spi->master);
+       u32 uma_cfg = BIT(10);
+       u32 data_reg[4];
+       int ret;
+       u32 val;
+       u32 i;
+
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                          NPCM_FIU_UMA_CTS_DEV_NUM,
+                          (mem->spi->chip_select <<
+                           NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
+                          NPCM_FIU_UMA_CMD_CMD, op->cmd.opcode);
+
+       if (is_address_size) {
+               uma_cfg |= ilog2(op->cmd.buswidth);
+               uma_cfg |= ilog2(op->addr.buswidth)
+                       << NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
+               uma_cfg |= ilog2(op->dummy.buswidth)
+                       << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
+               uma_cfg |= ilog2(op->data.buswidth)
+                       << NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
+               uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
+               uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
+               regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, addr);
+       } else {
+               regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
+       }
+
+       uma_cfg |= data_size << NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT;
+       regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
+       regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                         NPCM_FIU_UMA_CTS_EXEC_DONE,
+                         NPCM_FIU_UMA_CTS_EXEC_DONE);
+       ret = regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
+                                      (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
+                                      UMA_MICRO_SEC_TIMEOUT);
+       if (ret)
+               return ret;
+
+       if (data_size) {
+               for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
+                       regmap_read(fiu->regmap, NPCM_FIU_UMA_DR0 + (i * 4),
+                                   &data_reg[i]);
+               memcpy(data, data_reg, data_size);
+       }
+
+       return 0;
+}
+
+static int npcm_fiu_uma_write(struct spi_mem *mem,
+                             const struct spi_mem_op *op, u8 cmd,
+                             bool is_address_size, u8 *data, u32 data_size)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(mem->spi->master);
+       u32 uma_cfg = BIT(10);
+       u32 data_reg[4] = {0};
+       u32 val;
+       u32 i;
+
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                          NPCM_FIU_UMA_CTS_DEV_NUM,
+                          (mem->spi->chip_select <<
+                           NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
+
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
+                          NPCM_FIU_UMA_CMD_CMD, cmd);
+
+       if (data_size) {
+               memcpy(data_reg, data, data_size);
+               for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
+                       regmap_write(fiu->regmap, NPCM_FIU_UMA_DW0 + (i * 4),
+                                    data_reg[i]);
+       }
+
+       if (is_address_size) {
+               uma_cfg |= ilog2(op->cmd.buswidth);
+               uma_cfg |= ilog2(op->addr.buswidth) <<
+                       NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
+               uma_cfg |= ilog2(op->data.buswidth) <<
+                       NPCM_FIU_UMA_CFG_WDBPCK_SHIFT;
+               uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
+               regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, op->addr.val);
+       } else {
+               regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
+       }
+
+       uma_cfg |= (data_size << NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT);
+       regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
+
+       regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                         NPCM_FIU_UMA_CTS_EXEC_DONE,
+                         NPCM_FIU_UMA_CTS_EXEC_DONE);
+
+       return regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
+                                      (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
+                                       UMA_MICRO_SEC_TIMEOUT);
+}
+
+static int npcm_fiu_manualwrite(struct spi_mem *mem,
+                               const struct spi_mem_op *op)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(mem->spi->master);
+       u8 *data = (u8 *)op->data.buf.out;
+       u32 num_data_chunks;
+       u32 remain_data;
+       u32 idx = 0;
+       int ret;
+
+       num_data_chunks  = op->data.nbytes / CHUNK_SIZE;
+       remain_data  = op->data.nbytes % CHUNK_SIZE;
+
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                          NPCM_FIU_UMA_CTS_DEV_NUM,
+                          (mem->spi->chip_select <<
+                           NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                          NPCM_FIU_UMA_CTS_SW_CS, 0);
+
+       ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, true, NULL, 0);
+       if (ret)
+               return ret;
+
+       /* Starting the data writing loop in multiples of 8 */
+       for (idx = 0; idx < num_data_chunks; ++idx) {
+               ret = npcm_fiu_uma_write(mem, op, data[0], false,
+                                        &data[1], CHUNK_SIZE - 1);
+               if (ret)
+                       return ret;
+
+               data += CHUNK_SIZE;
+       }
+
+       /* Handling chunk remains */
+       if (remain_data > 0) {
+               ret = npcm_fiu_uma_write(mem, op, data[0], false,
+                                        &data[1], remain_data - 1);
+               if (ret)
+                       return ret;
+       }
+
+       regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
+                          NPCM_FIU_UMA_CTS_SW_CS, NPCM_FIU_UMA_CTS_SW_CS);
+
+       return 0;
+}
+
+static int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       u8 *data = op->data.buf.in;
+       int i, readlen, currlen;
+       u8 *buf_ptr;
+       u32 addr;
+       int ret;
+
+       i = 0;
+       currlen = op->data.nbytes;
+
+       do {
+               addr = ((u32)op->addr.val + i);
+               if (currlen < 16)
+                       readlen = currlen;
+               else
+                       readlen = 16;
+
+               buf_ptr = data + i;
+               ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr,
+                                       readlen);
+               if (ret)
+                       return ret;
+
+               i += readlen;
+               currlen -= 16;
+       } while (currlen > 0);
+
+       return 0;
+}
+
+static void npcm_fiux_set_direct_wr(struct npcm_fiu_spi *fiu)
+{
+       regmap_write(fiu->regmap, NPCM_FIU_DWR_CFG,
+                    NPCM_FIU_DWR_16_BYTE_BURST);
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
+                          NPCM_FIU_DWR_CFG_ABPCK,
+                          DWR_ABPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_ABPCK_SHIFT);
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
+                          NPCM_FIU_DWR_CFG_DBPCK,
+                          DWR_DBPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_DBPCK_SHIFT);
+}
+
+static void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
+{
+       u32 rx_dummy = 0;
+
+       regmap_write(fiu->regmap, NPCM_FIU_DRD_CFG,
+                    NPCM_FIU_DRD_16_BYTE_BURST);
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_ACCTYPE,
+                          DRD_SPI_X_MODE << NPCM_FIU_DRD_ACCTYPE_SHIFT);
+       regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
+                          NPCM_FIU_DRD_CFG_DBW,
+                          rx_dummy << NPCM_FIU_DRD_DBW_SHIFT);
+}
+
+static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(mem->spi->master);
+       struct npcm_fiu_chip *chip = &fiu->chip[mem->spi->chip_select];
+       int ret = 0;
+       u8 *buf;
+
+       dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
+               op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+               op->dummy.buswidth, op->data.buswidth, op->addr.val,
+               op->data.nbytes);
+
+       if (fiu->spix_mode || op->addr.nbytes > 4)
+               return -ENOTSUPP;
+
+       if (fiu->clkrate != chip->clkrate) {
+               ret = clk_set_rate(fiu->clk, chip->clkrate);
+               if (ret < 0)
+                       dev_warn(fiu->dev, "Failed setting %lu frequency, stay at %lu frequency\n",
+                                chip->clkrate, fiu->clkrate);
+               else
+                       fiu->clkrate = chip->clkrate;
+       }
+
+       if (op->data.dir == SPI_MEM_DATA_IN) {
+               if (!op->addr.nbytes) {
+                       buf = op->data.buf.in;
+                       ret = npcm_fiu_uma_read(mem, op, op->addr.val, false,
+                                               buf, op->data.nbytes);
+               } else {
+                       ret = npcm_fiu_read(mem, op);
+               }
+       } else  {
+               if (!op->addr.nbytes && !op->data.nbytes)
+                       ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
+                                                NULL, 0);
+               if (op->addr.nbytes && !op->data.nbytes) {
+                       int i;
+                       u8 buf_addr[4];
+                       u32 addr = op->addr.val;
+
+                       for (i = op->addr.nbytes - 1; i >= 0; i--) {
+                               buf_addr[i] = addr & 0xff;
+                               addr >>= 8;
+                       }
+                       ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
+                                                buf_addr, op->addr.nbytes);
+               }
+               if (!op->addr.nbytes && op->data.nbytes)
+                       ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
+                                                (u8 *)op->data.buf.out,
+                                                op->data.nbytes);
+               if (op->addr.nbytes && op->data.nbytes)
+                       ret = npcm_fiu_manualwrite(mem, op);
+       }
+
+       return ret;
+}
+
+static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+       struct npcm_fiu_spi *fiu =
+               spi_controller_get_devdata(desc->mem->spi->master);
+       struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
+       struct regmap *gcr_regmap;
+
+       if (!fiu->res_mem) {
+               dev_warn(fiu->dev, "Reserved memory not defined, direct read disabled\n");
+               desc->nodirmap = true;
+               return 0;
+       }
+
+       if (!fiu->spix_mode &&
+           desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
+               desc->nodirmap = true;
+               return 0;
+       }
+
+       if (!chip->flash_region_mapped_ptr) {
+               chip->flash_region_mapped_ptr =
+                       devm_ioremap_nocache(fiu->dev, (fiu->res_mem->start +
+                                                       (fiu->info->max_map_size *
+                                                   desc->mem->spi->chip_select)),
+                                            (u32)desc->info.length);
+               if (!chip->flash_region_mapped_ptr) {
+                       dev_warn(fiu->dev, "Error mapping memory region, direct read disabled\n");
+                       desc->nodirmap = true;
+                       return 0;
+               }
+       }
+
+       if (of_device_is_compatible(fiu->dev->of_node, "nuvoton,npcm750-fiu")) {
+               gcr_regmap =
+                       syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+               if (IS_ERR(gcr_regmap)) {
+                       dev_warn(fiu->dev, "Didn't find nuvoton,npcm750-gcr, direct read disabled\n");
+                       desc->nodirmap = true;
+                       return 0;
+               }
+               regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
+                                  NPCM7XX_INTCR3_FIU_FIX,
+                                  NPCM7XX_INTCR3_FIU_FIX);
+       }
+
+       if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
+               if (!fiu->spix_mode)
+                       npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
+               else
+                       npcm_fiux_set_direct_rd(fiu);
+
+       } else {
+               npcm_fiux_set_direct_wr(fiu);
+       }
+
+       return 0;
+}
+
+static int npcm_fiu_setup(struct spi_device *spi)
+{
+       struct spi_controller *ctrl = spi->master;
+       struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
+       struct npcm_fiu_chip *chip;
+
+       chip = &fiu->chip[spi->chip_select];
+       chip->fiu = fiu;
+       chip->chipselect = spi->chip_select;
+       chip->clkrate = spi->max_speed_hz;
+
+       fiu->clkrate = clk_get_rate(fiu->clk);
+
+       return 0;
+}
+
+static const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
+       .exec_op = npcm_fiu_exec_op,
+       .dirmap_create = npcm_fiu_dirmap_create,
+       .dirmap_read = npcm_fiu_direct_read,
+       .dirmap_write = npcm_fiu_direct_write,
+};
+
+static const struct of_device_id npcm_fiu_dt_ids[] = {
+       { .compatible = "nuvoton,npcm750-fiu", .data = &npxm7xx_fiu_data  },
+       { /* sentinel */ }
+};
+
+static int npcm_fiu_probe(struct platform_device *pdev)
+{
+       const struct fiu_data *fiu_data_match;
+       const struct of_device_id *match;
+       struct device *dev = &pdev->dev;
+       struct spi_controller *ctrl;
+       struct npcm_fiu_spi *fiu;
+       void __iomem *regbase;
+       struct resource *res;
+       int ret;
+       int id;
+
+       ctrl = spi_alloc_master(dev, sizeof(*fiu));
+       if (!ctrl)
+               return -ENOMEM;
+
+       fiu = spi_controller_get_devdata(ctrl);
+
+       match = of_match_device(npcm_fiu_dt_ids, dev);
+       if (!match || !match->data) {
+               dev_err(dev, "No compatible OF match\n");
+               return -ENODEV;
+       }
+
+       fiu_data_match = match->data;
+       id = of_alias_get_id(dev->of_node, "fiu");
+       if (id < 0 || id >= fiu_data_match->fiu_max) {
+               dev_err(dev, "Invalid platform device id: %d\n", id);
+               return -EINVAL;
+       }
+
+       fiu->info = &fiu_data_match->npcm_fiu_data_info[id];
+
+       platform_set_drvdata(pdev, fiu);
+       fiu->dev = dev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
+       regbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regbase))
+               return PTR_ERR(regbase);
+
+       fiu->regmap = devm_regmap_init_mmio(dev, regbase,
+                                           &npcm_mtd_regmap_config);
+       if (IS_ERR(fiu->regmap)) {
+               dev_err(dev, "Failed to create regmap\n");
+               return PTR_ERR(fiu->regmap);
+       }
+
+       fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                   "memory");
+       fiu->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(fiu->clk))
+               return PTR_ERR(fiu->clk);
+
+       fiu->spix_mode = of_property_read_bool(dev->of_node,
+                                              "nuvoton,spix-mode");
+
+       platform_set_drvdata(pdev, fiu);
+       clk_prepare_enable(fiu->clk);
+
+       ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
+               | SPI_TX_DUAL | SPI_TX_QUAD;
+       ctrl->setup = npcm_fiu_setup;
+       ctrl->bus_num = -1;
+       ctrl->mem_ops = &npcm_fiu_mem_ops;
+       ctrl->num_chipselect = fiu->info->max_cs;
+       ctrl->dev.of_node = dev->of_node;
+
+       ret = devm_spi_register_master(dev, ctrl);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int npcm_fiu_remove(struct platform_device *pdev)
+{
+       struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(fiu->clk);
+       return 0;
+}
+
+MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids);
+
+static struct platform_driver npcm_fiu_driver = {
+       .driver = {
+               .name   = "NPCM-FIU",
+               .bus    = &platform_bus_type,
+               .of_match_table = npcm_fiu_dt_ids,
+       },
+       .probe      = npcm_fiu_probe,
+       .remove     = npcm_fiu_remove,
+};
+module_platform_driver(npcm_fiu_driver);
+
+MODULE_DESCRIPTION("Nuvoton FLASH Interface Unit SPI Controller Driver");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
index 734a2b9..b191d57 100644 (file)
@@ -341,7 +341,6 @@ static int npcm_pspi_probe(struct platform_device *pdev)
 {
        struct npcm_pspi *priv;
        struct spi_master *master;
-       struct resource *res;
        unsigned long clk_hz;
        struct device_node *np = pdev->dev.of_node;
        int num_cs, i;
@@ -368,8 +367,7 @@ static int npcm_pspi_probe(struct platform_device *pdev)
        priv->is_save_param = false;
        priv->id = pdev->id;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base)) {
                ret = PTR_ERR(priv->base);
                goto out_master_put;
@@ -388,7 +386,6 @@ static int npcm_pspi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get IRQ\n");
                ret = irq;
                goto out_disable_clk;
        }
index 37e2034..6140035 100644 (file)
@@ -327,7 +327,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
 {
        struct nuc900_spi *hw;
        struct spi_master *master;
-       struct resource *res;
        int err = 0;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@@ -358,8 +357,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
        hw->bitbang.chipselect     = nuc900_spi_chipsel;
        hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->regs = devm_ioremap_resource(&pdev->dev, res);
+       hw->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->regs)) {
                err = PTR_ERR(hw->regs);
                goto err_pdata;
@@ -367,7 +365,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
 
        hw->irq = platform_get_irq(pdev, 0);
        if (hw->irq < 0) {
-               dev_err(&pdev->dev, "No IRQ specified\n");
                err = -ENOENT;
                goto err_pdata;
        }
index 8894f98..501b923 100644 (file)
@@ -1007,10 +1007,8 @@ static int nxp_fspi_probe(struct platform_device *pdev)
 
        /* find the irq */
        ret = platform_get_irq(pdev, 0);
-       if (ret < 0) {
-               dev_err(dev, "failed to get the irq: %d\n", ret);
+       if (ret < 0)
                goto err_disable_clk;
-       }
 
        ret = devm_request_irq(dev, ret,
                        nxp_fspi_irq_handler, 0, pdev->name, f);
index bbc4ba6..e2331eb 100644 (file)
@@ -240,7 +240,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
        struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
        struct tiny_spi *hw;
        struct spi_master *master;
-       struct resource *res;
        unsigned int i;
        int err = -ENODEV;
 
@@ -264,8 +263,7 @@ static int tiny_spi_probe(struct platform_device *pdev)
        hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
 
        /* find and map our resources */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->base = devm_ioremap_resource(&pdev->dev, res);
+       hw->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->base)) {
                err = PTR_ERR(hw->base);
                goto exit;
index b635526..86ad175 100644 (file)
@@ -570,7 +570,6 @@ static int pic32_sqi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct pic32_sqi *sqi;
-       struct resource *reg;
        int ret;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*sqi));
@@ -580,8 +579,7 @@ static int pic32_sqi_probe(struct platform_device *pdev)
        sqi = spi_master_get_devdata(master);
        sqi->master = master;
 
-       reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sqi->regs = devm_ioremap_resource(&pdev->dev, reg);
+       sqi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sqi->regs)) {
                ret = PTR_ERR(sqi->regs);
                goto err_free_master;
@@ -590,7 +588,6 @@ static int pic32_sqi_probe(struct platform_device *pdev)
        /* irq */
        sqi->irq = platform_get_irq(pdev, 0);
        if (sqi->irq < 0) {
-               dev_err(&pdev->dev, "no irq found\n");
                ret = sqi->irq;
                goto err_free_master;
        }
index 10cebea..69f517e 100644 (file)
@@ -711,22 +711,16 @@ static int pic32_spi_hw_probe(struct platform_device *pdev,
 
        /* get irq resources: err-irq, rx-irq, tx-irq */
        pic32s->fault_irq = platform_get_irq_byname(pdev, "fault");
-       if (pic32s->fault_irq < 0) {
-               dev_err(&pdev->dev, "fault-irq not found\n");
+       if (pic32s->fault_irq < 0)
                return pic32s->fault_irq;
-       }
 
        pic32s->rx_irq = platform_get_irq_byname(pdev, "rx");
-       if (pic32s->rx_irq < 0) {
-               dev_err(&pdev->dev, "rx-irq not found\n");
+       if (pic32s->rx_irq < 0)
                return pic32s->rx_irq;
-       }
 
        pic32s->tx_irq = platform_get_irq_byname(pdev, "tx");
-       if (pic32s->tx_irq < 0) {
-               dev_err(&pdev->dev, "tx-irq not found\n");
+       if (pic32s->tx_irq < 0)
                return pic32s->tx_irq;
-       }
 
        /* get clock */
        pic32s->clk = devm_clk_get(&pdev->dev, "mck0");
index e0f0611..250fd60 100644 (file)
@@ -424,7 +424,6 @@ static int qcom_qspi_probe(struct platform_device *pdev)
 {
        int ret;
        struct device *dev;
-       struct resource *res;
        struct spi_master *master;
        struct qcom_qspi *ctrl;
 
@@ -440,8 +439,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
 
        spin_lock_init(&ctrl->lock);
        ctrl->dev = dev;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ctrl->base = devm_ioremap_resource(dev, res);
+       ctrl->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ctrl->base)) {
                ret = PTR_ERR(ctrl->base);
                goto exit_probe_master_put;
@@ -454,10 +452,8 @@ static int qcom_qspi_probe(struct platform_device *pdev)
                goto exit_probe_master_put;
 
        ret = platform_get_irq(pdev, 0);
-       if (ret < 0) {
-               dev_err(dev, "Failed to get irq %d\n", ret);
+       if (ret < 0)
                goto exit_probe_master_put;
-       }
        ret = devm_request_irq(dev, ret, qcom_qspi_irq,
                        IRQF_TRIGGER_HIGH, dev_name(dev), ctrl);
        if (ret) {
index 51f03d9..4c9620e 100644 (file)
@@ -135,12 +135,10 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct clk *ahb_clk;
        struct rb4xx_spi *rbspi;
-       struct resource *r;
        int err;
        void __iomem *spi_base;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spi_base = devm_ioremap_resource(&pdev->dev, r);
+       spi_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spi_base))
                return PTR_ERR(spi_base);
 
index 48d8dff..2d6e37f 100644 (file)
@@ -487,7 +487,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
        struct s3c2410_spi_info *pdata;
        struct s3c24xx_spi *hw;
        struct spi_master *master;
-       struct resource *res;
        int err = 0;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
@@ -536,8 +535,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
        dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
 
        /* find and map our resources */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->regs = devm_ioremap_resource(&pdev->dev, res);
+       hw->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hw->regs)) {
                err = PTR_ERR(hw->regs);
                goto err_no_pdata;
@@ -545,7 +543,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
 
        hw->irq = platform_get_irq(pdev, 0);
        if (hw->irq < 0) {
-               dev_err(&pdev->dev, "No IRQ specified\n");
                err = -ENOENT;
                goto err_no_pdata;
        }
index b50bdbc..8f13473 100644 (file)
@@ -1297,7 +1297,6 @@ static void sh_msiof_release_dma(struct sh_msiof_spi_priv *p)
 
 static int sh_msiof_spi_probe(struct platform_device *pdev)
 {
-       struct resource *r;
        struct spi_controller *ctlr;
        const struct sh_msiof_chipdata *chipdata;
        struct sh_msiof_spi_info *info;
@@ -1346,13 +1345,11 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
 
        i = platform_get_irq(pdev, 0);
        if (i < 0) {
-               dev_err(&pdev->dev, "cannot get IRQ\n");
                ret = i;
                goto err1;
        }
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       p->mapbase = devm_ioremap_resource(&pdev->dev, r);
+       p->mapbase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(p->mapbase)) {
                ret = PTR_ERR(p->mapbase);
                goto err1;
index f1ee582..20bdae5 100644 (file)
@@ -437,10 +437,8 @@ static int spi_sh_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "platform_get_irq error: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));
        if (master == NULL) {
index 93ec2c6..35254bd 100644 (file)
@@ -292,7 +292,6 @@ sifive_spi_transfer_one(struct spi_master *master, struct spi_device *device,
 static int sifive_spi_probe(struct platform_device *pdev)
 {
        struct sifive_spi *spi;
-       struct resource *res;
        int ret, irq, num_cs;
        u32 cs_bits, max_bits_per_word;
        struct spi_master *master;
@@ -307,8 +306,7 @@ static int sifive_spi_probe(struct platform_device *pdev)
        init_completion(&spi->done);
        platform_set_drvdata(pdev, master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spi->regs = devm_ioremap_resource(&pdev->dev, res);
+       spi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spi->regs)) {
                ret = PTR_ERR(spi->regs);
                goto put_master;
@@ -323,7 +321,6 @@ static int sifive_spi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "Unable to find interrupt\n");
                ret = irq;
                goto put_master;
        }
index 71b882a..e1e6391 100644 (file)
@@ -1070,7 +1070,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
 {
        struct sirfsoc_spi *sspi;
        struct spi_master *master;
-       struct resource *mem_res;
        const struct sirf_spi_comp_data *spi_comp_data;
        int irq;
        int ret;
@@ -1097,8 +1096,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1;
        sspi->dat_max_frm_len = spi_comp_data->dat_max_frm_len;
        sspi->fifo_size = spi_comp_data->fifo_size;
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
+       sspi->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sspi->base)) {
                ret = PTR_ERR(sspi->base);
                goto free_master;
index d107543..61bc43b 100644 (file)
@@ -410,7 +410,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
 
        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_ctlr;
        }
index df5960b..9a05128 100644 (file)
@@ -86,6 +86,7 @@
 #define BIT_WDG_EN                     BIT(2)
 
 /* Definition of PMIC reset status register */
+#define HWRST_STATUS_SECURITY          0x02
 #define HWRST_STATUS_RECOVERY          0x20
 #define HWRST_STATUS_NORMAL            0x40
 #define HWRST_STATUS_ALARM             0x50
@@ -97,6 +98,8 @@
 #define HWRST_STATUS_AUTODLOADER       0xa0
 #define HWRST_STATUS_IQMODE            0xb0
 #define HWRST_STATUS_SPRDISK           0xc0
+#define HWRST_STATUS_FACTORYTEST       0xe0
+#define HWRST_STATUS_WATCHDOG          0xf0
 
 /* Use default timeout 50 ms that converts to watchdog values */
 #define WDG_LOAD_VAL                   ((50 * 1000) / 32768)
@@ -162,14 +165,16 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
        int read_timeout = ADI_READ_TIMEOUT;
        unsigned long flags;
        u32 val, rd_addr;
-       int ret;
-
-       ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
-                                         ADI_HWSPINLOCK_TIMEOUT,
-                                         &flags);
-       if (ret) {
-               dev_err(sadi->dev, "get the hw lock failed\n");
-               return ret;
+       int ret = 0;
+
+       if (sadi->hwlock) {
+               ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+                                                 ADI_HWSPINLOCK_TIMEOUT,
+                                                 &flags);
+               if (ret) {
+                       dev_err(sadi->dev, "get the hw lock failed\n");
+                       return ret;
+               }
        }
 
        /*
@@ -216,7 +221,8 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
        *read_val = val & RD_VALUE_MASK;
 
 out:
-       hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+       if (sadi->hwlock)
+               hwspin_unlock_irqrestore(sadi->hwlock, &flags);
        return ret;
 }
 
@@ -227,12 +233,14 @@ static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val)
        unsigned long flags;
        int ret;
 
-       ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
-                                         ADI_HWSPINLOCK_TIMEOUT,
-                                         &flags);
-       if (ret) {
-               dev_err(sadi->dev, "get the hw lock failed\n");
-               return ret;
+       if (sadi->hwlock) {
+               ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
+                                                 ADI_HWSPINLOCK_TIMEOUT,
+                                                 &flags);
+               if (ret) {
+                       dev_err(sadi->dev, "get the hw lock failed\n");
+                       return ret;
+               }
        }
 
        ret = sprd_adi_drain_fifo(sadi);
@@ -258,7 +266,8 @@ static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val)
        }
 
 out:
-       hwspin_unlock_irqrestore(sadi->hwlock, &flags);
+       if (sadi->hwlock)
+               hwspin_unlock_irqrestore(sadi->hwlock, &flags);
        return ret;
 }
 
@@ -307,6 +316,18 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr,
        return 0;
 }
 
+static void sprd_adi_set_wdt_rst_mode(struct sprd_adi *sadi)
+{
+#ifdef CONFIG_SPRD_WATCHDOG
+       u32 val;
+
+       /* Set default watchdog reboot mode */
+       sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val);
+       val |= HWRST_STATUS_WATCHDOG;
+       sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val);
+#endif
+}
+
 static int sprd_adi_restart_handler(struct notifier_block *this,
                                    unsigned long mode, void *cmd)
 {
@@ -336,11 +357,16 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
                reboot_mode = HWRST_STATUS_IQMODE;
        else if (!strncmp(cmd, "sprdisk", 7))
                reboot_mode = HWRST_STATUS_SPRDISK;
+       else if (!strncmp(cmd, "tospanic", 8))
+               reboot_mode = HWRST_STATUS_SECURITY;
+       else if (!strncmp(cmd, "factorytest", 11))
+               reboot_mode = HWRST_STATUS_FACTORYTEST;
        else
                reboot_mode = HWRST_STATUS_NORMAL;
 
        /* Record the reboot mode */
        sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val);
+       val &= ~HWRST_STATUS_WATCHDOG;
        val |= reboot_mode;
        sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val);
 
@@ -380,9 +406,6 @@ static void sprd_adi_hw_init(struct sprd_adi *sadi)
        const __be32 *list;
        u32 tmp;
 
-       /* Address bits select default 12 bits */
-       writel_relaxed(0, sadi->base + REG_ADI_CTRL0);
-
        /* Set all channels as default priority */
        writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIL);
        writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIH);
@@ -459,19 +482,30 @@ static int sprd_adi_probe(struct platform_device *pdev)
        sadi->slave_pbase = res->start + ADI_SLAVE_OFFSET;
        sadi->ctlr = ctlr;
        sadi->dev = &pdev->dev;
-       ret = of_hwspin_lock_get_id_byname(np, "adi");
-       if (ret < 0) {
-               dev_err(&pdev->dev, "can not get the hardware spinlock\n");
-               goto put_ctlr;
-       }
-
-       sadi->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, ret);
-       if (!sadi->hwlock) {
-               ret = -ENXIO;
-               goto put_ctlr;
+       ret = of_hwspin_lock_get_id(np, 0);
+       if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0)) {
+               sadi->hwlock =
+                       devm_hwspin_lock_request_specific(&pdev->dev, ret);
+               if (!sadi->hwlock) {
+                       ret = -ENXIO;
+                       goto put_ctlr;
+               }
+       } else {
+               switch (ret) {
+               case -ENOENT:
+                       dev_info(&pdev->dev, "no hardware spinlock supplied\n");
+                       break;
+               default:
+                       dev_err(&pdev->dev,
+                               "failed to find hwlock id, %d\n", ret);
+                       /* fall-through */
+               case -EPROBE_DEFER:
+                       goto put_ctlr;
+               }
        }
 
        sprd_adi_hw_init(sadi);
+       sprd_adi_set_wdt_rst_mode(sadi);
 
        ctlr->dev.of_node = pdev->dev.of_node;
        ctlr->bus_num = pdev->id;
index 1b7eebb..8c9021b 100644 (file)
@@ -843,10 +843,8 @@ static int sprd_spi_irq_init(struct platform_device *pdev, struct sprd_spi *ss)
        int ret;
 
        ss->irq = platform_get_irq(pdev, 0);
-       if (ss->irq < 0) {
-               dev_err(&pdev->dev, "failed to get irq resource\n");
+       if (ss->irq < 0)
                return ss->irq;
-       }
 
        ret = devm_request_irq(&pdev->dev, ss->irq, sprd_spi_handle_irq,
                                0, pdev->name, ss);
index 840a6bf..0c24c49 100644 (file)
@@ -298,7 +298,6 @@ static int spi_st_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct spi_master *master;
-       struct resource *res;
        struct spi_st *spi_st;
        int irq, ret = 0;
        u32 var;
@@ -331,8 +330,7 @@ static int spi_st_probe(struct platform_device *pdev)
        init_completion(&spi_st->done);
 
        /* Get resources */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       spi_st->base = devm_ioremap_resource(&pdev->dev, res);
+       spi_st->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(spi_st->base)) {
                ret = PTR_ERR(spi_st->base);
                goto clk_disable;
index 655e4af..9ac6f9f 100644 (file)
@@ -570,11 +570,8 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               if (irq != -EPROBE_DEFER)
-                       dev_err(dev, "IRQ error missing or invalid\n");
+       if (irq < 0)
                return irq;
-       }
 
        ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
                               dev_name(dev), qspi);
index 5194bc0..cbfac65 100644 (file)
@@ -428,7 +428,6 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct sun4i_spi *sspi;
-       struct resource *res;
        int ret = 0, irq;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
@@ -440,8 +439,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
        sspi = spi_master_get_devdata(master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sspi->base_addr)) {
                ret = PTR_ERR(sspi->base_addr);
                goto err_free_master;
@@ -449,7 +447,6 @@ static int sun4i_spi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "No spi IRQ specified\n");
                ret = -ENXIO;
                goto err_free_master;
        }
index ee2bdaf..ec7967b 100644 (file)
@@ -435,7 +435,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct sun6i_spi *sspi;
-       struct resource *res;
        int ret = 0, irq;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
@@ -447,8 +446,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
        sspi = spi_master_get_devdata(master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sspi->base_addr)) {
                ret = PTR_ERR(sspi->base_addr);
                goto err_free_master;
@@ -456,7 +454,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "No spi IRQ specified\n");
                ret = -ENXIO;
                goto err_free_master;
        }
index f99abd8..ae17c99 100644 (file)
@@ -670,7 +670,6 @@ static int synquacer_spi_probe(struct platform_device *pdev)
 
        rx_irq = platform_get_irq(pdev, 0);
        if (rx_irq <= 0) {
-               dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq);
                ret = rx_irq;
                goto put_spi;
        }
@@ -685,7 +684,6 @@ static int synquacer_spi_probe(struct platform_device *pdev)
 
        tx_irq = platform_get_irq(pdev, 1);
        if (tx_irq <= 0) {
-               dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq);
                ret = tx_irq;
                goto put_spi;
        }
index cd714a4..a841a72 100644 (file)
@@ -419,7 +419,6 @@ static int tegra_sflash_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
        struct tegra_sflash_data        *tsd;
-       struct resource         *r;
        int ret;
        const struct of_device_id *match;
 
@@ -451,8 +450,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
                                 &master->max_speed_hz))
                master->max_speed_hz = 25000000; /* 25MHz */
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tsd->base = devm_ioremap_resource(&pdev->dev, r);
+       tsd->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(tsd->base)) {
                ret = PTR_ERR(tsd->base);
                goto exit_free_master;
index 6ca6007..3cb6537 100644 (file)
@@ -717,7 +717,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq resource?\n");
                ret = irq;
                goto free_master;
        }
index b32c77d..47cde18 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -16,6 +17,7 @@
 #include <asm/unaligned.h>
 
 #define SSI_TIMEOUT_MS         2000
+#define SSI_POLL_TIMEOUT_US    200
 #define SSI_MAX_CLK_DIVIDER    254
 #define SSI_MIN_CLK_DIVIDER    4
 
@@ -214,6 +216,7 @@ static void uniphier_spi_setup_transfer(struct spi_device *spi,
        if (!priv->is_save_param || priv->mode != spi->mode) {
                uniphier_spi_set_mode(spi);
                priv->mode = spi->mode;
+               priv->is_save_param = false;
        }
 
        if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
@@ -226,8 +229,7 @@ static void uniphier_spi_setup_transfer(struct spi_device *spi,
                priv->speed_hz = t->speed_hz;
        }
 
-       if (!priv->is_save_param)
-               priv->is_save_param = true;
+       priv->is_save_param = true;
 
        /* reset FIFOs */
        val = SSI_FC_TXFFL | SSI_FC_RXFFL;
@@ -290,21 +292,23 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
 
 static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
 {
-       unsigned int tx_count;
+       unsigned int fifo_threshold, fill_bytes;
        u32 val;
 
-       tx_count = DIV_ROUND_UP(priv->tx_bytes,
+       fifo_threshold = DIV_ROUND_UP(priv->rx_bytes,
                                bytes_per_word(priv->bits_per_word));
-       tx_count = min(tx_count, SSI_FIFO_DEPTH);
+       fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
+
+       fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes);
 
        /* set fifo threshold */
        val = readl(priv->base + SSI_FC);
        val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
-       val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count);
-       val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count);
+       val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold);
+       val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold);
        writel(val, priv->base + SSI_FC);
 
-       while (tx_count--)
+       while (fill_bytes--)
                uniphier_spi_send(priv);
 }
 
@@ -323,20 +327,14 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
        writel(val, priv->base + SSI_FPS);
 }
 
-static int uniphier_spi_transfer_one(struct spi_master *master,
-                                    struct spi_device *spi,
-                                    struct spi_transfer *t)
+static int uniphier_spi_transfer_one_irq(struct spi_master *master,
+                                        struct spi_device *spi,
+                                        struct spi_transfer *t)
 {
        struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
        struct device *dev = master->dev.parent;
        unsigned long time_left;
 
-       /* Terminate and return success for 0 byte length transfer */
-       if (!t->len)
-               return 0;
-
-       uniphier_spi_setup_transfer(spi, t);
-
        reinit_completion(&priv->xfer_done);
 
        uniphier_spi_fill_tx_fifo(priv);
@@ -356,6 +354,59 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
        return priv->error;
 }
 
+static int uniphier_spi_transfer_one_poll(struct spi_master *master,
+                                         struct spi_device *spi,
+                                         struct spi_transfer *t)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+       int loop = SSI_POLL_TIMEOUT_US * 10;
+
+       while (priv->tx_bytes) {
+               uniphier_spi_fill_tx_fifo(priv);
+
+               while ((priv->rx_bytes - priv->tx_bytes) > 0) {
+                       while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE)
+                                                               && loop--)
+                               ndelay(100);
+
+                       if (loop == -1)
+                               goto irq_transfer;
+
+                       uniphier_spi_recv(priv);
+               }
+       }
+
+       return 0;
+
+irq_transfer:
+       return uniphier_spi_transfer_one_irq(master, spi, t);
+}
+
+static int uniphier_spi_transfer_one(struct spi_master *master,
+                                    struct spi_device *spi,
+                                    struct spi_transfer *t)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+       unsigned long threshold;
+
+       /* Terminate and return success for 0 byte length transfer */
+       if (!t->len)
+               return 0;
+
+       uniphier_spi_setup_transfer(spi, t);
+
+       /*
+        * If the transfer operation will take longer than
+        * SSI_POLL_TIMEOUT_US, it should use irq.
+        */
+       threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz,
+                                       USEC_PER_SEC * BITS_PER_BYTE);
+       if (t->len > threshold)
+               return uniphier_spi_transfer_one_irq(master, spi, t);
+       else
+               return uniphier_spi_transfer_one_poll(master, spi, t);
+}
+
 static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
 {
        struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
@@ -419,7 +470,6 @@ static int uniphier_spi_probe(struct platform_device *pdev)
 {
        struct uniphier_spi_priv *priv;
        struct spi_master *master;
-       struct resource *res;
        unsigned long clk_rate;
        int irq;
        int ret;
@@ -434,8 +484,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
        priv->master = master;
        priv->is_save_param = false;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base)) {
                ret = PTR_ERR(priv->base);
                goto out_master_put;
@@ -454,7 +503,6 @@ static int uniphier_spi_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get IRQ\n");
                ret = irq;
                goto out_disable_clk;
        }
index 1dc479f..797ac0e 100644 (file)
@@ -370,7 +370,6 @@ static int xlp_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct xlp_spi_priv *xspi;
-       struct resource *res;
        struct clk *clk;
        int irq, err;
 
@@ -378,16 +377,13 @@ static int xlp_spi_probe(struct platform_device *pdev)
        if (!xspi)
                return -ENOMEM;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xspi->base = devm_ioremap_resource(&pdev->dev, res);
+       xspi->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xspi->base))
                return PTR_ERR(xspi->base);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
        err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0,
                        pdev->name, xspi);
        if (err) {
index c6bee67..5cf6993 100644 (file)
@@ -620,7 +620,6 @@ static int zynq_qspi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct zynq_qspi *xqspi;
-       struct resource *res;
        u32 num_cs;
 
        ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
@@ -630,8 +629,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
        xqspi = spi_controller_get_devdata(ctlr);
        xqspi->dev = dev;
        platform_set_drvdata(pdev, xqspi);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xqspi->regs = devm_ioremap_resource(&pdev->dev, res);
+       xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xqspi->regs)) {
                ret = PTR_ERR(xqspi->regs);
                goto remove_master;
@@ -671,7 +669,6 @@ static int zynq_qspi_probe(struct platform_device *pdev)
        xqspi->irq = platform_get_irq(pdev, 0);
        if (xqspi->irq <= 0) {
                ret = -ENXIO;
-               dev_err(&pdev->dev, "irq resource not found\n");
                goto remove_master;
        }
        ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq,
@@ -695,7 +692,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
        ctlr->setup = zynq_qspi_setup_op;
        ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
        ctlr->dev.of_node = np;
-       ret = spi_register_controller(ctlr);
+       ret = devm_spi_register_controller(&pdev->dev, ctlr);
        if (ret) {
                dev_err(&pdev->dev, "spi_register_master failed\n");
                goto clk_dis_all;
index 07a83ca..60c4de4 100644 (file)
@@ -1016,7 +1016,6 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        int ret = 0;
        struct spi_master *master;
        struct zynqmp_qspi *xqspi;
-       struct resource *res;
        struct device *dev = &pdev->dev;
 
        eemi_ops = zynqmp_pm_get_eemi_ops();
@@ -1031,8 +1030,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        master->dev.of_node = pdev->dev.of_node;
        platform_set_drvdata(pdev, master);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       xqspi->regs = devm_ioremap_resource(&pdev->dev, res);
+       xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(xqspi->regs)) {
                ret = PTR_ERR(xqspi->regs);
                goto remove_master;
@@ -1077,7 +1075,6 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        xqspi->irq = platform_get_irq(pdev, 0);
        if (xqspi->irq <= 0) {
                ret = -ENXIO;
-               dev_err(dev, "irq resource not found\n");
                goto clk_dis_all;
        }
        ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq,
index 75ac046..f8b4654 100644 (file)
@@ -1265,8 +1265,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
  */
 static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 {
-       unsigned long flags;
+       struct spi_message *msg;
        bool was_busy = false;
+       unsigned long flags;
        int ret;
 
        /* Lock queue */
@@ -1325,10 +1326,10 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
        }
 
        /* Extract head of queue */
-       ctlr->cur_msg =
-               list_first_entry(&ctlr->queue, struct spi_message, queue);
+       msg = list_first_entry(&ctlr->queue, struct spi_message, queue);
+       ctlr->cur_msg = msg;
 
-       list_del_init(&ctlr->cur_msg->queue);
+       list_del_init(&msg->queue);
        if (ctlr->busy)
                was_busy = true;
        else
@@ -1361,7 +1362,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                        if (ctlr->auto_runtime_pm)
                                pm_runtime_put(ctlr->dev.parent);
 
-                       ctlr->cur_msg->status = ret;
+                       msg->status = ret;
                        spi_finalize_current_message(ctlr);
 
                        mutex_unlock(&ctlr->io_mutex);
@@ -1369,28 +1370,28 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                }
        }
 
-       trace_spi_message_start(ctlr->cur_msg);
+       trace_spi_message_start(msg);
 
        if (ctlr->prepare_message) {
-               ret = ctlr->prepare_message(ctlr, ctlr->cur_msg);
+               ret = ctlr->prepare_message(ctlr, msg);
                if (ret) {
                        dev_err(&ctlr->dev, "failed to prepare message: %d\n",
                                ret);
-                       ctlr->cur_msg->status = ret;
+                       msg->status = ret;
                        spi_finalize_current_message(ctlr);
                        goto out;
                }
                ctlr->cur_msg_prepared = true;
        }
 
-       ret = spi_map_msg(ctlr, ctlr->cur_msg);
+       ret = spi_map_msg(ctlr, msg);
        if (ret) {
-               ctlr->cur_msg->status = ret;
+               msg->status = ret;
                spi_finalize_current_message(ctlr);
                goto out;
        }
 
-       ret = ctlr->transfer_one_message(ctlr, ctlr->cur_msg);
+       ret = ctlr->transfer_one_message(ctlr, msg);
        if (ret) {
                dev_err(&ctlr->dev,
                        "failed to transfer one message from queue\n");
@@ -1434,7 +1435,7 @@ static void spi_pump_messages(struct kthread_work *work)
  */
 static void spi_set_thread_rt(struct spi_controller *ctlr)
 {
-       struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+       struct sched_param param = { .sched_priority = MAX_RT_PRIO / 2 };
 
        dev_info(&ctlr->dev,
                "will run message pump with realtime priority\n");
@@ -2105,8 +2106,8 @@ static int match_true(struct device *dev, void *data)
        return 1;
 }
 
-static ssize_t spi_slave_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
+static ssize_t slave_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
 {
        struct spi_controller *ctlr = container_of(dev, struct spi_controller,
                                                   dev);
@@ -2117,9 +2118,8 @@ static ssize_t spi_slave_show(struct device *dev,
                       child ? to_spi_device(child)->modalias : NULL);
 }
 
-static ssize_t spi_slave_store(struct device *dev,
-                              struct device_attribute *attr, const char *buf,
-                              size_t count)
+static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
 {
        struct spi_controller *ctlr = container_of(dev, struct spi_controller,
                                                   dev);
@@ -2157,7 +2157,7 @@ static ssize_t spi_slave_store(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(slave, 0644, spi_slave_show, spi_slave_store);
+static DEVICE_ATTR_RW(slave);
 
 static struct attribute *spi_slave_attrs[] = {
        &dev_attr_slave.attr,
@@ -2188,8 +2188,10 @@ extern struct class spi_slave_class;     /* dummy */
  * __spi_alloc_controller - allocate an SPI master or slave controller
  * @dev: the controller, possibly using the platform_bus
  * @size: how much zeroed driver-private data to allocate; the pointer to this
- *     memory is in the driver_data field of the returned device,
- *     accessible with spi_controller_get_devdata().
+ *     memory is in the driver_data field of the returned device, accessible
+ *     with spi_controller_get_devdata(); the memory is cacheline aligned;
+ *     drivers granting DMA access to portions of their private data need to
+ *     round up @size using ALIGN(size, dma_get_cache_alignment()).
  * @slave: flag indicating whether to allocate an SPI master (false) or SPI
  *     slave (true) controller
  * Context: can sleep
@@ -2211,11 +2213,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
                                              unsigned int size, bool slave)
 {
        struct spi_controller   *ctlr;
+       size_t ctlr_size = ALIGN(sizeof(*ctlr), dma_get_cache_alignment());
 
        if (!dev)
                return NULL;
 
-       ctlr = kzalloc(size + sizeof(*ctlr), GFP_KERNEL);
+       ctlr = kzalloc(size + ctlr_size, GFP_KERNEL);
        if (!ctlr)
                return NULL;
 
@@ -2229,14 +2232,14 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
                ctlr->dev.class = &spi_master_class;
        ctlr->dev.parent = dev;
        pm_suspend_ignore_children(&ctlr->dev, true);
-       spi_controller_set_devdata(ctlr, &ctlr[1]);
+       spi_controller_set_devdata(ctlr, (void *)ctlr + ctlr_size);
 
        return ctlr;
 }
 EXPORT_SYMBOL_GPL(__spi_alloc_controller);
 
 #ifdef CONFIG_OF
-static int of_spi_register_master(struct spi_controller *ctlr)
+static int of_spi_get_gpio_numbers(struct spi_controller *ctlr)
 {
        int nb, i, *cs;
        struct device_node *np = ctlr->dev.of_node;
@@ -2269,7 +2272,7 @@ static int of_spi_register_master(struct spi_controller *ctlr)
        return 0;
 }
 #else
-static int of_spi_register_master(struct spi_controller *ctlr)
+static int of_spi_get_gpio_numbers(struct spi_controller *ctlr)
 {
        return 0;
 }
@@ -2456,7 +2459,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                        ctlr->mode_bits |= SPI_CS_HIGH;
                } else {
                        /* Legacy code path for GPIOs from DT */
-                       status = of_spi_register_master(ctlr);
+                       status = of_spi_get_gpio_numbers(ctlr);
                        if (status)
                                return status;
                }
index 2edf3ee..caf4d4d 100644 (file)
@@ -342,9 +342,9 @@ static irqreturn_t dt3k_interrupt(int irq, void *d)
 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
                            unsigned int flags)
 {
-       int divider, base, prescale;
+       unsigned int divider, base, prescale;
 
-       /* This function needs improvment */
+       /* This function needs improvement */
        /* Don't know if divider==0 works. */
 
        for (prescale = 0; prescale < 16; prescale++) {
@@ -358,7 +358,7 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
                        divider = (*nanosec) / base;
                        break;
                case CMDF_ROUND_UP:
-                       divider = (*nanosec) / base;
+                       divider = DIV_ROUND_UP(*nanosec, base);
                        break;
                }
                if (divider < 65536) {
@@ -368,7 +368,7 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
        }
 
        prescale = 15;
-       base = timer_base * (1 << prescale);
+       base = timer_base * (prescale + 1);
        divider = 65535;
        *nanosec = divider * base;
        return (prescale << 16) | (divider);
index 04eda11..661bb93 100644 (file)
@@ -1132,14 +1132,16 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
        struct se_cmd *se_cmd = cmd->se_cmd;
        struct tcmu_dev *udev = cmd->tcmu_dev;
        bool read_len_valid = false;
-       uint32_t read_len = se_cmd->data_length;
+       uint32_t read_len;
 
        /*
         * cmd has been completed already from timeout, just reclaim
         * data area space and free cmd
         */
-       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
+       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+               WARN_ON_ONCE(se_cmd);
                goto out;
+       }
 
        list_del_init(&cmd->queue_entry);
 
@@ -1152,6 +1154,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
                goto done;
        }
 
+       read_len = se_cmd->data_length;
        if (se_cmd->data_direction == DMA_FROM_DEVICE &&
            (entry->hdr.uflags & TCMU_UFLAG_READ_LEN) && entry->rsp.read_len) {
                read_len_valid = true;
@@ -1307,6 +1310,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
                 */
                scsi_status = SAM_STAT_CHECK_CONDITION;
                list_del_init(&cmd->queue_entry);
+               cmd->se_cmd = NULL;
        } else {
                list_del_init(&cmd->queue_entry);
                idr_remove(&udev->commands, id);
@@ -2022,6 +2026,7 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level)
 
                idr_remove(&udev->commands, i);
                if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+                       WARN_ON(!cmd->se_cmd);
                        list_del_init(&cmd->queue_entry);
                        if (err_level == 1) {
                                /*
index 518aac9..514169e 100644 (file)
@@ -856,16 +856,6 @@ config SERIAL_CPM_CONSOLE
          your boot loader (lilo or loadlin) about how to pass options to the
          kernel at boot time.)
 
-config SERIAL_SGI_L1_CONSOLE
-       bool "SGI Altix L1 serial console support"
-       depends on IA64_GENERIC || IA64_SGI_SN2
-       select SERIAL_CORE
-       select SERIAL_CORE_CONSOLE
-       help
-               If you have an SGI Altix and you would like to use the system
-               controller serial port as your console (you want this!),
-               say Y.  Otherwise, say N.
-
 config SERIAL_PIC32
        tristate "Microchip PIC32 serial support"
        depends on MACH_PIC32
@@ -983,23 +973,6 @@ config SERIAL_JSM
          To compile this driver as a module, choose M here: the
          module will be called jsm.
 
-config SERIAL_SGI_IOC4
-       tristate "SGI IOC4 controller serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
-       select SERIAL_CORE
-       help
-               If you have an SGI Altix with an IOC4 based Base IO card
-               and wish to use the serial ports on this card, say Y.
-               Otherwise, say N.
-
-config SERIAL_SGI_IOC3
-       tristate "SGI Altix IOC3 serial support"
-       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
-       select SERIAL_CORE
-       help
-         If you have an SGI Altix with an IOC3 serial card,
-         say Y or M.  Otherwise, say N.
-
 config SERIAL_MSM
        tristate "MSM on-chip serial port support"
        depends on ARCH_QCOM
index 15a0fcc..d2f4487 100644 (file)
@@ -41,7 +41,6 @@ obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
-obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
 obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
 obj-$(CONFIG_SERIAL_IMX) += imx.o
 obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
@@ -53,8 +52,6 @@ obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
-obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
-obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
 obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
deleted file mode 100644 (file)
index d8a1cdd..0000000
+++ /dev/null
@@ -1,2195 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-/*
- * This file contains a module version of the ioc3 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/ioc3.h>
-#include <linux/slab.h>
-
-/*
- * Interesting things about the ioc3
- */
-
-#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
-#define PORTS_PER_CARD         2
-#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
-#define MAX_CARDS              8
-#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
-
-/* determine given the sio_ir what port it applies to */
-#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
-
-
-/*
- * we have 2 logical ports (rs232, rs422) for each physical port
- * evens are rs232, odds are rs422
- */
-#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
-#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
-#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
-#define IS_RS232(_x)           !((_x) & 1)
-
-static unsigned int Num_of_ioc3_cards;
-static unsigned int Submodule_slot;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...)  printk _x
-#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS()       printk("%s : fails %d\n", __func__, __LINE__)
-
-/* number of characters we want to transmit to the lower level at a time */
-#define MAX_CHARS              256
-#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
-
-/* Device name we're using */
-#define DEVICE_NAME            "ttySIOC"
-#define DEVICE_MAJOR           204
-#define DEVICE_MINOR           116
-
-/* flags for next_char_state */
-#define NCS_BREAK              0x1
-#define NCS_PARITY             0x2
-#define NCS_FRAMING            0x4
-#define NCS_OVERRUN            0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232            0
-#define PROTO_RS422            1
-
-/* Notification types */
-#define N_DATA_READY           0x01
-#define N_OUTPUT_LOWAT         0x02
-#define N_BREAK                        0x04
-#define N_PARITY_ERROR         0x08
-#define N_FRAMING_ERROR                0x10
-#define N_OVERRUN_ERROR                0x20
-#define N_DDCD                 0x40
-#define N_DCTS                 0x80
-
-#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
-                                               | N_OVERRUN_ERROR)
-
-#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
-                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
-                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
-#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
-#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
-
-#define RING_BUF_SIZE          4096
-#define BUF_SIZE_BIT           SBBR_L_SIZE
-#define PROD_CONS_MASK         PROD_CONS_PTR_4K
-
-#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
-
-/* driver specific - one per card */
-struct ioc3_card {
-       struct {
-               /* uart ports are allocated here */
-               struct uart_port icp_uart_port[LOGICAL_PORTS];
-               /* the ioc3_port used for this port */
-               struct ioc3_port *icp_port;
-       } ic_port[PORTS_PER_CARD];
-       /* currently enabled interrupts */
-       uint32_t ic_enable;
-};
-
-/* Local port info for each IOC3 serial port */
-struct ioc3_port {
-       /* handy reference material */
-       struct uart_port *ip_port;
-       struct ioc3_card *ip_card;
-       struct ioc3_driver_data *ip_idd;
-       struct ioc3_submodule *ip_is;
-
-       /* pci mem addresses for this port */
-       struct ioc3_serialregs __iomem *ip_serial_regs;
-       struct ioc3_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct port_hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH             0x01
-       /* used to signify that we have turned off the rx_high
-        * temporarily - we need to drain the fifo and don't
-        * want to get blasted with interrupts.
-        */
-#define DCD_ON                 0x02
-       /* DCD state is on */
-#define LOWAT_WRITTEN          0x04
-#define READ_ABORTED           0x08
-       /* the read was aborted - used to avaoid infinate looping
-        * in the interrupt handler
-        */
-#define INPUT_ENABLE           0x10
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct port_hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       char rs422_select_pin;
-};
-
-static struct port_hooks hooks_array[PORTS_PER_CARD] = {
-       /* values for port A */
-       {
-       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SA_TX_MT,
-       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
-       .intr_rx_high = SIO_IR_SA_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
-                               | SIO_IR_SA_RX_HIGH
-                               | SIO_IR_SA_RX_TIMER
-                               | SIO_IR_SA_DELTA_DCD
-                               | SIO_IR_SA_DELTA_CTS
-                               | SIO_IR_SA_INT
-                               | SIO_IR_SA_TX_EXPLICIT
-                               | SIO_IR_SA_MEMERR),
-       .intr_all =  SIO_IR_SA,
-       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
-        },
-
-       /* values for port B */
-       {
-       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
-       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
-       .intr_tx_mt = SIO_IR_SB_TX_MT,
-       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
-       .intr_rx_high = SIO_IR_SB_RX_HIGH,
-       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
-       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
-                               | SIO_IR_SB_RX_HIGH
-                               | SIO_IR_SB_RX_TIMER
-                               | SIO_IR_SB_DELTA_DCD
-                               | SIO_IR_SB_DELTA_CTS
-                               | SIO_IR_SB_INT
-                               | SIO_IR_SB_TX_EXPLICIT
-                               | SIO_IR_SB_MEMERR),
-       .intr_all = SIO_IR_SB,
-       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
-        }
-};
-
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc                u.s.sc
-#define ring_data      u.s.data
-#define ring_allsc     u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_A;
-       struct ring RX_A;
-       struct ring TX_B;
-       struct ring RX_B;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* for Infinite loop detection  */
-#define MAXITER                10000000
-
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc3_port *port, int baud)
-{
-       int divisor;
-       int actual_baud;
-       int diff;
-       int lcr, prediv;
-       struct ioc3_uartregs __iomem *uart;
-
-       for (prediv = 6; prediv < 64; prediv++) {
-               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
-               if (!divisor)
-                       continue;       /* invalid divisor */
-               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
-
-               diff = actual_baud - baud;
-               if (diff < 0)
-                       diff = -diff;
-
-               /* if we're within 1% we've found a match */
-               if (diff * 100 <= actual_baud)
-                       break;
-       }
-
-       /* if the above loop completed, we didn't match
-        * the baud rate.  give up.
-        */
-       if (prediv == 64) {
-               NOT_PROGRESS();
-               return 1;
-       }
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->iu_lcr);
-
-       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
-       writeb((unsigned char)divisor, &uart->iu_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
-       writeb((unsigned char)prediv, &uart->iu_scr);
-       writeb((unsigned char)lcr, &uart->iu_lcr);
-
-       return 0;
-}
-
-/**
- * get_ioc3_port - given a uart port, return the control structure
- * @the_port: uart port to find
- */
-static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
-{
-       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
-       int ii, jj;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return NULL;
-       }
-       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
-               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
-                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
-                               return card_ptr->ic_port[ii].icp_port;
-               }
-       }
-       NOT_PROGRESS();
-       return NULL;
-}
-
-/**
- * port_init - Initialize the sio and ioc3 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static inline int port_init(struct ioc3_port *port)
-{
-       uint32_t sio_cr;
-       struct port_hooks *hooks = port->ip_hooks;
-       struct ioc3_uartregs __iomem *uart;
-       int reset_loop_counter = 0xfffff;
-       struct ioc3_driver_data *idd = port->ip_idd;
-
-       /* Idle the IOC3 serial interface */
-       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do {
-               sio_cr = readl(&idd->vma->sio_cr);
-               if (reset_loop_counter-- <= 0) {
-                       printk(KERN_WARNING
-                              "IOC3 unable to come out of reset"
-                               " scr 0x%x\n", sio_cr);
-                       return -1;
-               }
-       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
-              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
-               || sio_cr == SIO_CR_ARB_DIAG_TXB
-               || sio_cr == SIO_CR_ARB_DIAG_RXA
-               || sio_cr == SIO_CR_ARB_DIAG_RXB));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->iu_lcr);
-       writeb(0, &uart->iu_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-              &uart->iu_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->iu_mcr);
-
-       /* Clear deltas in modem status register */
-       writel(0, &port->ip_serial_regs->shadow);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l, *sbbr_h;
-
-               sbbr_l = &idd->vma->sbbr_l;
-               sbbr_h = &idd->vma->sbbr_h;
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
-                              __func__, (void *)ring_pci_addr));
-
-               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-
-       /* uart experiences pauses at high baud rate reducing actual
-        * throughput by 10% or so unless we enable high speed polling
-        * XXX when this hardware bug is resolved we should revert to
-        * normal polling speed
-        */
-       port->ip_sscr |= SSCR_HIGH_SPD;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       port->ip_card->ic_enable &= ~hooks->intr_clear;
-       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
-       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
-       return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if ((port->ip_card->ic_enable & mask) != mask) {
-               port->ip_card->ic_enable |= mask;
-               ioc3_enable(port->ip_is, port->ip_idd, mask);
-       }
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc3_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = INPUT_ENABLE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               NOT_PROGRESS();
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-              &port->ip_uart_regs->iu_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
-       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * SRTR_HZ / HZ
-        */
-       timeout = timeout * SRTR_HZ / 100;
-       if (timeout > SRTR_CNT)
-               timeout = SRTR_CNT;
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc3_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
-                       "parodd %d\n",
-                      __func__, ((struct uart_port *)port->ip_port)->line,
-                       baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->iu_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->iu_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc3_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
-               port->ip_sscr |= SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
-{
-       if (port->ip_card->ic_enable & mask) {
-               ioc3_disable(port->ip_is, port->ip_idd, mask);
-               port->ip_card->ic_enable &= ~mask;
-       }
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc3_port *port, int mask, int set_on)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= SSCR_DMA_EN;
-       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
-               port->ip_sscr &= ~SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-                         int mask1, int mask2)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr | SSCR_DMA_PAUSE,
-                      &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                       & SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-       writeb(mcr, &port->ip_uart_regs->iu_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc3_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc3_set_proto(struct ioc3_port *port, int proto)
-{
-       struct port_hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       default:
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs232\n", __func__));
-               writel(0, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               DPRINT_CONFIG(("%s: rs422\n", __func__));
-               writel(1, (&port->ip_idd->vma->gppr[0]
-                                       + hooks->rs422_select_pin));
-               break;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with the_port->lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc3_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc3_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned int cflag, iflag;
-       int baud;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               break;
-       case CS6:
-               new_data = 6;
-               break;
-       case CS7:
-               new_data = 7;
-               break;
-       case CS8:
-               new_data = 8;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
-                               the_port->line));
-
-       if (!the_port->fifosize)
-               the_port->fifosize = FIFO_SIZE;
-       uart_update_timeout(the_port, cflag, baud);
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                                 | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               /* enable hardware flow control */
-               port->ip_sscr |= SSCR_HFC_EN;
-       }
-       else {
-               /* disable hardware flow control */
-               port->ip_sscr &= ~SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
-                      "config_port(baud %d data %d stop %d penable %d "
-                       " parity %d), notification 0x%x\n",
-                      __func__, (void *)port, the_port->line, cflag, baud,
-                      new_data, new_stop, new_parity_enable, new_parity,
-                      the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,    /* baud */
-                        new_data,      /* byte size */
-                        new_stop,      /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic3_startup_local(struct uart_port *the_port)
-{
-       struct ioc3_port *port;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -1;
-       }
-
-       local_open(port);
-
-       /* set the protocol */
-       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
-                                                       PROTO_RS422);
-       return 0;
-}
-
-/*
- * ioc3_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
- */
-static void ioc3_cb_output_lowat(struct ioc3_port *port)
-{
-       unsigned long pflags;
-
-       /* the_port->lock is set on the call here */
-       if (port->ip_port) {
-               spin_lock_irqsave(&port->ip_port->lock, pflags);
-               transmit_chars(port->ip_port);
-               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
-       }
-}
-
-/*
- * ioc3_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct port_hooks *hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-       hooks = port->ip_hooks;
-
-       /* There is a nasty timing issue in the IOC3. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-
-       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & SSCR_DMA_EN)) {
-                       port->ip_sscr |= SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | SSCR_RX_DRAIN,
-                      &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                              SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                           & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on read (line %d).\n",
-                               the_port->line);
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & RXSB_MODEM_VALID)
-                           && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-                               if ((port->ip_flags & DCD_ON)
-                                   && !(*sc & RXSB_DCD)) {
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                           == 0) {
-                                               cons_ptr += (int)sizeof
-                                                   (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                              &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                           && port->ip_port) {
-                                               uart_handle_dcd_change
-                                                       (port->ip_port, 0);
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                    port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & RXSB_DATA_VALID) &&
-                           ((*sc & (RXSB_PAR_ERR
-                                    | RXSB_FRAME_ERR | RXSB_BREAK))
-                            && (port->ip_notify & (N_PARITY_ERROR
-                                                   | N_FRAMING_ERROR
-                                                   | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & RXSB_PAR_ERR) &&
-                                           (port->
-                                            ip_notify & N_PARITY_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_PARITY);
-                                       }
-                                       if ((*sc & RXSB_FRAME_ERR) &&
-                                           (port->
-                                            ip_notify & N_FRAMING_ERROR)) {
-                                               ioc3_cb_post_ncs(the_port,
-                                                                NCS_FRAMING);
-                                       }
-                                       if ((*sc & RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                               ioc3_cb_post_ncs
-                                                   (the_port, NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & RXSB_DATA_VALID) {
-                               *sc &= ~RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                                              & PROD_CONS_MASK) <
-                                             ((port->
-                                               ip_sscr &
-                                               SSCR_RX_THRESHOLD)
-                                              << PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read.
- * @the_port: port to read from
- */
-static int receive_chars(struct uart_port *the_port)
-{
-       unsigned char ch[MAX_CHARS];
-       int read_count = 0, read_room, flip = 0;
-       struct uart_state *state = the_port->state;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return 0;
-
-       if (!(port->ip_flags & INPUT_ENABLE))
-               return 0;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-
-       read_count = do_read(the_port, ch, MAX_CHARS);
-       if (read_count > 0) {
-               flip = 1;
-               read_room = tty_insert_flip_string(&state->port, ch,
-                               read_count);
-               the_port->icount.rx += read_count;
-       }
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       if (flip)
-               tty_flip_buffer_push(&state->port);
-
-       return read_count;
-}
-
-/**
- * ioc3uart_intr_one - lowest level (per port) interrupt handler.
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- */
-
-static inline int
-ioc3uart_intr_one(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int port_num = GET_PORT_FROM_SIO_IR(pending);
-       struct port_hooks *hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int loop_counter;
-       struct ioc3_card *card_ptr;
-       unsigned int sio_ir;
-
-       card_ptr = idd->data[is->id];
-       port = card_ptr->ic_port[port_num].icp_port;
-       hooks = port->ip_hooks;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-
-       sio_ir = pending & ~(hooks->intr_tx_mt);
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if (loop_counter-- <= 0) {
-                       printk(KERN_WARNING "IOC3 serial: "
-                              "possible hang condition/"
-                              "port stuck on interrupt (line %d).\n",
-                               ((struct uart_port *)port->ip_port)->line);
-                       break;
-               }
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                           && (shadow & SHADOW_DCD)
-                           && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_dcd_change(the_port,
-                                               shadow & SHADOW_DCD);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                  && !(shadow & SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               uart_handle_dcd_change(port->ip_port,
-                                               shadow & SHADOW_DCD);
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       ioc3_ack(is, idd, hooks->intr_delta_cts);
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               uart_handle_cts_change(the_port, shadow
-                                               & SHADOW_CTS);
-                               wake_up_interruptible
-                                   (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       ioc3_ack(is, idd, hooks->intr_rx_timer);
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && (port->ip_port)) {
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(card_ptr, idd))
-                                       & hooks->intr_rx_high) {
-                               if (port->ip_flags & READ_ABORTED) {
-                                       rx_high_rd_aborted++;
-                               }
-                               else {
-                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc3_cb_output_lowat(port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc3_cb_output_lowat(port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(card_ptr, idd);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                     & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                & SSCR_DMA_EN));
-                                       port->ip_sscr &= ~SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                              &port->ip_serial_regs->sscr);
-                               }
-                               /* Prevent infinite tx_mt interrupt */
-                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(card_ptr, idd);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-       ioc3_enable(is, idd, card_ptr->ic_enable);
-       return 0;
-}
-
-/**
- * ioc3uart_intr - field all serial interrupts
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- *
- */
-
-static int ioc3uart_intr(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd,
-                       unsigned int pending)
-{
-       int ret = 0;
-
-       /*
-        * The upper level interrupt handler sends interrupts for both ports
-        * here. So we need to call for each port with its interrupts.
-        */
-
-       if (pending & SIO_IR_SA)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
-       if (pending & SIO_IR_SB)
-               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
-
-       return ret;
-}
-
-/**
- * ic3_type
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic3_type(struct uart_port *the_port)
-{
-       if (IS_RS232(the_port->line))
-               return "SGI IOC3 Serial [rs232]";
-       else
-               return "SGI IOC3 Serial [rs422]";
-}
-
-/**
- * ic3_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic3_tx_empty(struct uart_port *the_port)
-{
-       unsigned int ret = 0;
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
-               ret = TIOCSER_TEMT;
-       return ret;
-}
-
-/**
- * ic3_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic3_stop_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * ic3_stop_rx - stop the receiver
- * @port: Port to operate on
- *
- */
-static void ic3_stop_rx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port)
-               port->ip_flags &= ~INPUT_ENABLE;
-}
-
-/**
- * null_void_function
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic3_shutdown - shut down the port - free irq and disable
- * @port: port to shut down
- *
- */
-static void ic3_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc3_port *port;
-       struct uart_state *state;
-
-       port = get_ioc3_port(the_port);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, SHADOW_DTR);
-}
-
-/**
- * ic3_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic3_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port)
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & SHADOW_DCD)
-               ret |= TIOCM_CD;
-       if (shadow & SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic3_start_tx - Start transmitter. Called with the_port->lock
- * @port: Port to operate on
- *
- */
-static void ic3_start_tx(struct uart_port *the_port)
-{
-       struct ioc3_port *port = get_ioc3_port(the_port);
-
-       if (port) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic3_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic3_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic3_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int ic3_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc3_port *port;
-       struct ioc3_card *card_ptr;
-       unsigned long port_flags;
-
-       if (!the_port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       port = get_ioc3_port(the_port);
-       if (!port) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-       card_ptr = port->ip_card;
-       port->ip_port = the_port;
-
-       if (!card_ptr) {
-               NOT_PROGRESS();
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic3_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic3_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic3_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc3_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic3_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-static const struct uart_ops ioc3_ops = {
-       .tx_empty = ic3_tx_empty,
-       .set_mctrl = ic3_set_mctrl,
-       .get_mctrl = ic3_get_mctrl,
-       .stop_tx = ic3_stop_tx,
-       .start_tx = ic3_start_tx,
-       .stop_rx = ic3_stop_rx,
-       .break_ctl = ic3_break_ctl,
-       .startup = ic3_startup,
-       .shutdown = ic3_shutdown,
-       .set_termios = ic3_set_termios,
-       .type = ic3_type,
-       .release_port = null_void_function,
-       .request_port = ic3_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc3_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "ioc3_serial",
-       .dev_name = DEVICE_NAME,
-       .major = DEVICE_MAJOR,
-       .minor = DEVICE_MINOR,
-       .nr = MAX_LOGICAL_PORTS
-};
-
-/**
- * ioc3_serial_core_attach - register with serial core
- *             This is done during pci probing
- * @is: submodule struct for this
- * @idd: handle for this card
- */
-static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
-                               struct ioc3_driver_data *idd)
-{
-       struct ioc3_port *port;
-       struct uart_port *the_port;
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       int ii, phys_port;
-       struct pci_dev *pdev = idd->pdev;
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
-                      __func__, pdev, (void *)card_ptr));
-
-       if (!card_ptr)
-               return -ENODEV;
-
-       /* once around for each logical port on this card */
-       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-               phys_port = GET_PHYSICAL_PORT(ii);
-               the_port = &card_ptr->ic_port[phys_port].
-                               icp_uart_port[GET_LOGICAL_PORT(ii)];
-               port = card_ptr->ic_port[phys_port].icp_port;
-               port->ip_port = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
-                       __func__, (void *)the_port, (void *)port,
-                               phys_port, ii));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  ii;
-               the_port->line = (Num_of_ioc3_cards << 2) | ii;
-               the_port->mapbase = 1;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = FIFO_SIZE;
-               the_port->ops = &ioc3_ops;
-               the_port->irq = idd->irq_io;
-               the_port->dev = &pdev->dev;
-
-               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
-                       printk(KERN_WARNING
-                         "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
-                         the_port->line, the_port->irq, pdev->bus->number));
-               }
-
-               /* all ports are rs232 for now */
-               if (IS_PHYSICAL_PORT(ii))
-                       ioc3_set_proto(port, PROTO_RS232);
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_remove - register detach function
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this submodule
- */
-
-static int ioc3uart_remove(struct ioc3_submodule *is,
-                       struct ioc3_driver_data *idd)
-{
-       struct ioc3_card *card_ptr = idd->data[is->id];
-       struct uart_port *the_port;
-       struct ioc3_port *port;
-       int ii;
-
-       if (card_ptr) {
-               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
-                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
-                       if (the_port)
-                               uart_remove_one_port(&ioc3_uart, the_port);
-                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
-                       if (port && IS_PHYSICAL_PORT(ii)
-                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
-                               pci_free_consistent(port->ip_idd->pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                               kfree(port);
-                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
-                                                       icp_port = NULL;
-                       }
-               }
-               kfree(card_ptr);
-               idd->data[is->id] = NULL;
-       }
-       return 0;
-}
-
-/**
- * ioc3uart_probe - card probe function called from shim driver
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this card
- */
-
-static int
-ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
-{
-       struct pci_dev *pdev = idd->pdev;
-       struct ioc3_card *card_ptr;
-       int ret = 0;
-       struct ioc3_port *port;
-       struct ioc3_port *ports[PORTS_PER_CARD];
-       int phys_port;
-       int cnt;
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
-
-       card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
-       if (!card_ptr) {
-               printk(KERN_WARNING "ioc3_attach_one"
-                      ": unable to get memory for the IOC3\n");
-               return -ENOMEM;
-       }
-       idd->data[is->id] = card_ptr;
-       Submodule_slot = is->id;
-
-       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
-               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
-               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
-
-       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
-
-       /* Create port structures for each port */
-       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
-               port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                              "IOC3 serial memory not available for port\n");
-                       ret = -ENOMEM;
-                       goto out4;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[phys_port] = port;
-
-               /* init to something useful */
-               card_ptr->ic_port[phys_port].icp_port = port;
-               port->ip_is = is;
-               port->ip_idd = idd;
-               port->ip_baud = 9600;
-               port->ip_card = card_ptr;
-               port->ip_hooks = &hooks_array[phys_port];
-
-               /* Setup each port */
-               if (phys_port == 0) {
-                       port->ip_serial_regs = &idd->vma->port_a;
-                       port->ip_uart_regs = &idd->vma->sregs.uarta;
-
-                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* setup ring buffers */
-                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
-                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
-
-                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
-                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       port->ip_inring = RING(port, RX_A);
-                       port->ip_outring = RING(port, TX_A);
-                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-               else {
-                       port->ip_serial_regs = &idd->vma->port_b;
-                       port->ip_uart_regs = &idd->vma->sregs.uartb;
-
-                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
-                                      "ip_uart_regs 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_serial_regs,
-                                      (void *)port->ip_uart_regs));
-
-                       /* share the ring buffers */
-                       port->ip_dma_ringbuf =
-                           ports[phys_port - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                           ports[phys_port - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_B);
-                       port->ip_outring = RING(port, TX_B);
-                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
-                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
-                                       "ip_outring 0x%p\n",
-                                      __func__,
-                                      (void *)port->ip_cpu_ringbuf,
-                                      (void *)port->ip_dma_ringbuf,
-                                      (void *)port->ip_inring,
-                                      (void *)port->ip_outring));
-               }
-
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
-                              __func__,
-                              phys_port, (void *)port, (void *)card_ptr));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                              (void *)port->ip_serial_regs,
-                              (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC3 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
-                              "outring 0x%p\n",
-                              __func__,
-                              phys_port, (void *)port,
-                              (void *)port->ip_inring,
-                              (void *)port->ip_outring));
-
-       }
-
-       /* register port with the serial core */
-
-       ret = ioc3_serial_core_attach(is, idd);
-       if (ret)
-               goto out4;
-
-       Num_of_ioc3_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out4:
-       for (cnt = 0; cnt < phys_port; cnt++)
-               kfree(ports[cnt]);
-
-       kfree(card_ptr);
-       return ret;
-}
-
-static struct ioc3_submodule ioc3uart_ops = {
-       .name = "IOC3uart",
-       .probe = ioc3uart_probe,
-       .remove = ioc3uart_remove,
-       /* call .intr for both ports initially */
-       .irq_mask = SIO_IR_SA | SIO_IR_SB,
-       .intr = ioc3uart_intr,
-       .owner = THIS_MODULE,
-};
-
-/**
- * ioc3_detect - module init called,
- */
-static int __init ioc3uart_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
-               printk(KERN_WARNING
-                      "%s: Couldn't register IOC3 uart serial driver\n",
-                      __func__);
-               return ret;
-       }
-       ret = ioc3_register_submodule(&ioc3uart_ops);
-       if (ret)
-               uart_unregister_driver(&ioc3_uart);
-       return ret;
-}
-
-static void __exit ioc3uart_exit(void)
-{
-       ioc3_unregister_submodule(&ioc3uart_ops);
-       uart_unregister_driver(&ioc3_uart);
-}
-
-module_init(ioc3uart_init);
-module_exit(ioc3uart_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
deleted file mode 100644 (file)
index db5b979..0000000
+++ /dev/null
@@ -1,2955 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-
-/*
- * This file contains a module version of the ioc4 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-/*
- * interesting things about the ioc4
- */
-
-#define IOC4_NUM_SERIAL_PORTS  4       /* max ports per card */
-#define IOC4_NUM_CARDS         8       /* max cards per partition */
-
-#define        GET_SIO_IR(_n)  (_n == 0) ? (IOC4_SIO_IR_S0) : \
-                               (_n == 1) ? (IOC4_SIO_IR_S1) : \
-                               (_n == 2) ? (IOC4_SIO_IR_S2) : \
-                               (IOC4_SIO_IR_S3)
-
-#define        GET_OTHER_IR(_n)  (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
-                               (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
-                               (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
-                               (IOC4_OTHER_IR_S3_MEMERR)
-
-
-/*
- * All IOC4 registers are 32 bits wide.
- */
-
-/*
- * PCI Memory Space Map
- */
-#define IOC4_PCI_ERR_ADDR_L     0x000  /* Low Error Address */
-#define IOC4_PCI_ERR_ADDR_VLD          (0x1 << 0)
-#define IOC4_PCI_ERR_ADDR_MST_ID_MSK    (0xf << 1)
-#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK   (0xe << 1)
-#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK   (0x1 << 1)
-#define IOC4_PCI_ERR_ADDR_MUL_ERR       (0x1 << 5)
-#define IOC4_PCI_ERR_ADDR_ADDR_MSK      (0x3ffffff << 6)
-
-/* Interrupt types */
-#define        IOC4_SIO_INTR_TYPE      0
-#define        IOC4_OTHER_INTR_TYPE    1
-#define        IOC4_NUM_INTR_TYPES     2
-
-/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
-#define IOC4_SIO_IR_S0_TX_MT      0x00000001   /* Serial port 0 TX empty */
-#define IOC4_SIO_IR_S0_RX_FULL    0x00000002   /* Port 0 RX buf full */
-#define IOC4_SIO_IR_S0_RX_HIGH    0x00000004   /* Port 0 RX hiwat */
-#define IOC4_SIO_IR_S0_RX_TIMER           0x00000008   /* Port 0 RX timeout */
-#define IOC4_SIO_IR_S0_DELTA_DCD   0x00000010  /* Port 0 delta DCD */
-#define IOC4_SIO_IR_S0_DELTA_CTS   0x00000020  /* Port 0 delta CTS */
-#define IOC4_SIO_IR_S0_INT        0x00000040   /* Port 0 pass-thru intr */
-#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080  /* Port 0 explicit TX thru */
-#define IOC4_SIO_IR_S1_TX_MT      0x00000100   /* Serial port 1 */
-#define IOC4_SIO_IR_S1_RX_FULL    0x00000200   /* */
-#define IOC4_SIO_IR_S1_RX_HIGH    0x00000400   /* */
-#define IOC4_SIO_IR_S1_RX_TIMER           0x00000800   /* */
-#define IOC4_SIO_IR_S1_DELTA_DCD   0x00001000  /* */
-#define IOC4_SIO_IR_S1_DELTA_CTS   0x00002000  /* */
-#define IOC4_SIO_IR_S1_INT        0x00004000   /* */
-#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000  /* */
-#define IOC4_SIO_IR_S2_TX_MT      0x00010000   /* Serial port 2 */
-#define IOC4_SIO_IR_S2_RX_FULL    0x00020000   /* */
-#define IOC4_SIO_IR_S2_RX_HIGH    0x00040000   /* */
-#define IOC4_SIO_IR_S2_RX_TIMER           0x00080000   /* */
-#define IOC4_SIO_IR_S2_DELTA_DCD   0x00100000  /* */
-#define IOC4_SIO_IR_S2_DELTA_CTS   0x00200000  /* */
-#define IOC4_SIO_IR_S2_INT        0x00400000   /* */
-#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000  /* */
-#define IOC4_SIO_IR_S3_TX_MT      0x01000000   /* Serial port 3 */
-#define IOC4_SIO_IR_S3_RX_FULL    0x02000000   /* */
-#define IOC4_SIO_IR_S3_RX_HIGH    0x04000000   /* */
-#define IOC4_SIO_IR_S3_RX_TIMER           0x08000000   /* */
-#define IOC4_SIO_IR_S3_DELTA_DCD   0x10000000  /* */
-#define IOC4_SIO_IR_S3_DELTA_CTS   0x20000000  /* */
-#define IOC4_SIO_IR_S3_INT        0x40000000   /* */
-#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000  /* */
-
-/* Per device interrupt masks */
-#define IOC4_SIO_IR_S0         (IOC4_SIO_IR_S0_TX_MT | \
-                                IOC4_SIO_IR_S0_RX_FULL | \
-                                IOC4_SIO_IR_S0_RX_HIGH | \
-                                IOC4_SIO_IR_S0_RX_TIMER | \
-                                IOC4_SIO_IR_S0_DELTA_DCD | \
-                                IOC4_SIO_IR_S0_DELTA_CTS | \
-                                IOC4_SIO_IR_S0_INT | \
-                                IOC4_SIO_IR_S0_TX_EXPLICIT)
-#define IOC4_SIO_IR_S1         (IOC4_SIO_IR_S1_TX_MT | \
-                                IOC4_SIO_IR_S1_RX_FULL | \
-                                IOC4_SIO_IR_S1_RX_HIGH | \
-                                IOC4_SIO_IR_S1_RX_TIMER | \
-                                IOC4_SIO_IR_S1_DELTA_DCD | \
-                                IOC4_SIO_IR_S1_DELTA_CTS | \
-                                IOC4_SIO_IR_S1_INT | \
-                                IOC4_SIO_IR_S1_TX_EXPLICIT)
-#define IOC4_SIO_IR_S2         (IOC4_SIO_IR_S2_TX_MT | \
-                                IOC4_SIO_IR_S2_RX_FULL | \
-                                IOC4_SIO_IR_S2_RX_HIGH | \
-                                IOC4_SIO_IR_S2_RX_TIMER | \
-                                IOC4_SIO_IR_S2_DELTA_DCD | \
-                                IOC4_SIO_IR_S2_DELTA_CTS | \
-                                IOC4_SIO_IR_S2_INT | \
-                                IOC4_SIO_IR_S2_TX_EXPLICIT)
-#define IOC4_SIO_IR_S3         (IOC4_SIO_IR_S3_TX_MT | \
-                                IOC4_SIO_IR_S3_RX_FULL | \
-                                IOC4_SIO_IR_S3_RX_HIGH | \
-                                IOC4_SIO_IR_S3_RX_TIMER | \
-                                IOC4_SIO_IR_S3_DELTA_DCD | \
-                                IOC4_SIO_IR_S3_DELTA_CTS | \
-                                IOC4_SIO_IR_S3_INT | \
-                                IOC4_SIO_IR_S3_TX_EXPLICIT)
-
-/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
-#define IOC4_OTHER_IR_ATA_INT          0x00000001  /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR       0x00000002  /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR                0x00000004  /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR                0x00000008  /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR                0x00000010  /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR                0x00000020  /* Port 3 PCI error */
-#define IOC4_OTHER_IR_KBD_INT          0x00000040  /* Keyboard/mouse */
-#define IOC4_OTHER_IR_RESERVED         0x007fff80  /* Reserved */
-#define IOC4_OTHER_IR_RT_INT           0x00800000  /* INT_OUT section output */
-#define IOC4_OTHER_IR_GEN_INT          0xff000000  /* Generic pins */
-
-#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
-                                 IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
-
-/* Bitmasks for IOC4_SIO_CR */
-#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0  /* byte bus strobe shift */
-#define IOC4_SIO_CR_ARB_DIAG_TX0       0x00000000
-#define IOC4_SIO_CR_ARB_DIAG_RX0       0x00000010
-#define IOC4_SIO_CR_ARB_DIAG_TX1       0x00000020
-#define IOC4_SIO_CR_ARB_DIAG_RX1       0x00000030
-#define IOC4_SIO_CR_ARB_DIAG_TX2       0x00000040
-#define IOC4_SIO_CR_ARB_DIAG_RX2       0x00000050
-#define IOC4_SIO_CR_ARB_DIAG_TX3       0x00000060
-#define IOC4_SIO_CR_ARB_DIAG_RX3       0x00000070
-#define IOC4_SIO_CR_SIO_DIAG_IDLE      0x00000080  /* 0 -> active request among
-                                                          serial ports (ro) */
-/* Defs for some of the generic I/O pins */
-#define IOC4_GPCR_UART0_MODESEL           0x10 /* Pin is output to port 0
-                                                  mode sel */
-#define IOC4_GPCR_UART1_MODESEL           0x20 /* Pin is output to port 1
-                                                  mode sel */
-#define IOC4_GPCR_UART2_MODESEL           0x40 /* Pin is output to port 2
-                                                  mode sel */
-#define IOC4_GPCR_UART3_MODESEL           0x80 /* Pin is output to port 3
-                                                  mode sel */
-
-#define IOC4_GPPR_UART0_MODESEL_PIN   4        /* GIO pin controlling
-                                          uart 0 mode select */
-#define IOC4_GPPR_UART1_MODESEL_PIN   5        /* GIO pin controlling
-                                          uart 1 mode select */
-#define IOC4_GPPR_UART2_MODESEL_PIN   6        /* GIO pin controlling
-                                          uart 2 mode select */
-#define IOC4_GPPR_UART3_MODESEL_PIN   7        /* GIO pin controlling
-                                          uart 3 mode select */
-
-/* Bitmasks for serial RX status byte */
-#define IOC4_RXSB_OVERRUN       0x01   /* Char(s) lost */
-#define IOC4_RXSB_PAR_ERR      0x02    /* Parity error */
-#define IOC4_RXSB_FRAME_ERR    0x04    /* Framing error */
-#define IOC4_RXSB_BREAK                0x08    /* Break character */
-#define IOC4_RXSB_CTS          0x10    /* State of CTS */
-#define IOC4_RXSB_DCD          0x20    /* State of DCD */
-#define IOC4_RXSB_MODEM_VALID   0x40   /* DCD, CTS, and OVERRUN are valid */
-#define IOC4_RXSB_DATA_VALID    0x80   /* Data byte, FRAME_ERR PAR_ERR
-                                        * & BREAK valid */
-
-/* Bitmasks for serial TX control byte */
-#define IOC4_TXCB_INT_WHEN_DONE 0x20   /* Interrupt after this byte is sent */
-#define IOC4_TXCB_INVALID      0x00    /* Byte is invalid */
-#define IOC4_TXCB_VALID                0x40    /* Byte is valid */
-#define IOC4_TXCB_MCR          0x80    /* Data<7:0> to modem control reg */
-#define IOC4_TXCB_DELAY                0xc0    /* Delay data<7:0> mSec */
-
-/* Bitmasks for IOC4_SBBR_L */
-#define IOC4_SBBR_L_SIZE       0x00000001  /* 0 == 1KB rings, 1 == 4KB rings */
-
-/* Bitmasks for IOC4_SSCR_<3:0> */
-#define IOC4_SSCR_RX_THRESHOLD  0x000001ff  /* Hiwater mark */
-#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000  /* TX timer in progress */
-#define IOC4_SSCR_HFC_EN       0x00020000  /* Hardware flow control enabled */
-#define IOC4_SSCR_RX_RING_DCD   0x00040000  /* Post RX record on delta-DCD */
-#define IOC4_SSCR_RX_RING_CTS   0x00080000  /* Post RX record on delta-CTS */
-#define IOC4_SSCR_DIAG         0x00200000  /* Bypass clock divider for sim */
-#define IOC4_SSCR_RX_DRAIN     0x08000000  /* Drain RX buffer to memory */
-#define IOC4_SSCR_DMA_EN       0x10000000  /* Enable ring buffer DMA */
-#define IOC4_SSCR_DMA_PAUSE    0x20000000  /* Pause DMA */
-#define IOC4_SSCR_PAUSE_STATE   0x40000000  /* Sets when PAUSE takes effect */
-#define IOC4_SSCR_RESET                0x80000000  /* Reset DMA channels */
-
-/* All producer/consumer pointers are the same bitfield */
-#define IOC4_PROD_CONS_PTR_4K   0x00000ff8     /* For 4K buffers */
-#define IOC4_PROD_CONS_PTR_1K   0x000003f8     /* For 1K buffers */
-#define IOC4_PROD_CONS_PTR_OFF           3
-
-/* Bitmasks for IOC4_SRCIR_<3:0> */
-#define IOC4_SRCIR_ARM         0x80000000      /* Arm RX timer */
-
-/* Bitmasks for IOC4_SHADOW_<3:0> */
-#define IOC4_SHADOW_DR  0x00000001     /* Data ready */
-#define IOC4_SHADOW_OE  0x00000002     /* Overrun error */
-#define IOC4_SHADOW_PE  0x00000004     /* Parity error */
-#define IOC4_SHADOW_FE  0x00000008     /* Framing error */
-#define IOC4_SHADOW_BI  0x00000010     /* Break interrupt */
-#define IOC4_SHADOW_THRE 0x00000020    /* Xmit holding register empty */
-#define IOC4_SHADOW_TEMT 0x00000040    /* Xmit shift register empty */
-#define IOC4_SHADOW_RFCE 0x00000080    /* Char in RX fifo has an error */
-#define IOC4_SHADOW_DCTS 0x00010000    /* Delta clear to send */
-#define IOC4_SHADOW_DDCD 0x00080000    /* Delta data carrier detect */
-#define IOC4_SHADOW_CTS         0x00100000     /* Clear to send */
-#define IOC4_SHADOW_DCD         0x00800000     /* Data carrier detect */
-#define IOC4_SHADOW_DTR         0x01000000     /* Data terminal ready */
-#define IOC4_SHADOW_RTS         0x02000000     /* Request to send */
-#define IOC4_SHADOW_OUT1 0x04000000    /* 16550 OUT1 bit */
-#define IOC4_SHADOW_OUT2 0x08000000    /* 16550 OUT2 bit */
-#define IOC4_SHADOW_LOOP 0x10000000    /* Loopback enabled */
-
-/* Bitmasks for IOC4_SRTR_<3:0> */
-#define IOC4_SRTR_CNT          0x00000fff      /* Reload value for RX timer */
-#define IOC4_SRTR_CNT_VAL      0x0fff0000      /* Current value of RX timer */
-#define IOC4_SRTR_CNT_VAL_SHIFT         16
-#define IOC4_SRTR_HZ                 16000     /* SRTR clock frequency */
-
-/* Serial port register map used for DMA and PIO serial I/O */
-struct ioc4_serialregs {
-       uint32_t sscr;
-       uint32_t stpir;
-       uint32_t stcir;
-       uint32_t srpir;
-       uint32_t srcir;
-       uint32_t srtr;
-       uint32_t shadow;
-};
-
-/* IOC4 UART register map */
-struct ioc4_uartregs {
-       char i4u_lcr;
-       union {
-               char iir;       /* read only */
-               char fcr;       /* write only */
-       } u3;
-       union {
-               char ier;       /* DLAB == 0 */
-               char dlm;       /* DLAB == 1 */
-       } u2;
-       union {
-               char rbr;       /* read only, DLAB == 0 */
-               char thr;       /* write only, DLAB == 0 */
-               char dll;       /* DLAB == 1 */
-       } u1;
-       char i4u_scr;
-       char i4u_msr;
-       char i4u_lsr;
-       char i4u_mcr;
-};
-
-/* short names */
-#define i4u_dll u1.dll
-#define i4u_ier u2.ier
-#define i4u_dlm u2.dlm
-#define i4u_fcr u3.fcr
-
-/* Serial port registers used for DMA serial I/O */
-struct ioc4_serial {
-       uint32_t sbbr01_l;
-       uint32_t sbbr01_h;
-       uint32_t sbbr23_l;
-       uint32_t sbbr23_h;
-
-       struct ioc4_serialregs port_0;
-       struct ioc4_serialregs port_1;
-       struct ioc4_serialregs port_2;
-       struct ioc4_serialregs port_3;
-       struct ioc4_uartregs uart_0;
-       struct ioc4_uartregs uart_1;
-       struct ioc4_uartregs uart_2;
-       struct ioc4_uartregs uart_3;
-};
-
-/* UART clock speed */
-#define IOC4_SER_XIN_CLK_66     66666667
-#define IOC4_SER_XIN_CLK_33     33333333
-
-#define IOC4_W_IES             0
-#define IOC4_W_IEC             1
-
-typedef void ioc4_intr_func_f(void *, uint32_t);
-typedef ioc4_intr_func_f *ioc4_intr_func_t;
-
-static unsigned int Num_of_ioc4_cards;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...)   ;
-//#define DPRINT_CONFIG(_x...) printk _x
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS   256
-
-/* number of characters we want to transmit to the lower level at a time */
-#define IOC4_MAX_CHARS 256
-#define IOC4_FIFO_CHARS        255
-
-/* Device name we're using */
-#define DEVICE_NAME_RS232  "ttyIOC"
-#define DEVICE_NAME_RS422  "ttyAIOC"
-#define DEVICE_MAJOR      204
-#define DEVICE_MINOR_RS232 50
-#define DEVICE_MINOR_RS422 84
-
-
-/* register offsets */
-#define IOC4_SERIAL_OFFSET     0x300
-
-/* flags for next_char_state */
-#define NCS_BREAK      0x1
-#define NCS_PARITY     0x2
-#define NCS_FRAMING    0x4
-#define NCS_OVERRUN    0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED     1200
-#define MAX_BAUD_SUPPORTED     115200
-
-/* protocol types supported */
-#define PROTO_RS232    3
-#define PROTO_RS422    7
-
-/* Notification types */
-#define N_DATA_READY   0x01
-#define N_OUTPUT_LOWAT 0x02
-#define N_BREAK                0x04
-#define N_PARITY_ERROR 0x08
-#define N_FRAMING_ERROR        0x10
-#define N_OVERRUN_ERROR        0x20
-#define N_DDCD         0x40
-#define N_DCTS         0x80
-
-#define N_ALL_INPUT    (N_DATA_READY | N_BREAK |                       \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT   N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS   (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
-
-#define N_ALL          (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK |      \
-                        N_PARITY_ERROR | N_FRAMING_ERROR |             \
-                        N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_DIVISOR(_x, clk)           (((clk) + (_x) * 8) / ((_x) * 16))
-#define DIVISOR_TO_BAUD(div, clk)      ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
-                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
-
-#define PENDING(_p)    (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
-#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
-
-/* Default to 4k buffers */
-#ifdef IOC4_1K_BUFFERS
-#define RING_BUF_SIZE 1024
-#define IOC4_BUF_SIZE_BIT 0
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
-#else
-#define RING_BUF_SIZE 4096
-#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
-#endif
-
-#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
-
-/*
- * This is the entry saved by the driver - one per card
- */
-
-#define UART_PORT_MIN          0
-#define UART_PORT_RS232                UART_PORT_MIN
-#define UART_PORT_RS422                1
-#define UART_PORT_COUNT                2       /* one for each mode */
-
-struct ioc4_control {
-       int ic_irq;
-       struct {
-               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
-               struct uart_port icp_uart_port[UART_PORT_COUNT];
-               /* Handy reference material */
-               struct ioc4_port *icp_port;
-       } ic_port[IOC4_NUM_SERIAL_PORTS];
-       struct ioc4_soft *ic_soft;
-};
-
-/*
- * per-IOC4 data structure
- */
-#define MAX_IOC4_INTR_ENTS     (8 * sizeof(uint32_t))
-struct ioc4_soft {
-       struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
-       struct ioc4_serial __iomem *is_ioc4_serial_addr;
-
-       /* Each interrupt type has an entry in the array */
-       struct ioc4_intr_type {
-
-               /*
-                * Each in-use entry in this array contains at least
-                * one nonzero bit in sd_bits; no two entries in this
-                * array have overlapping sd_bits values.
-                */
-               struct ioc4_intr_info {
-                       uint32_t sd_bits;
-                       ioc4_intr_func_f *sd_intr;
-                       void *sd_info;
-               } is_intr_info[MAX_IOC4_INTR_ENTS];
-
-               /* Number of entries active in the above array */
-               atomic_t is_num_intrs;
-       } is_intr_type[IOC4_NUM_INTR_TYPES];
-
-       /* is_ir_lock must be held while
-        * modifying sio_ie values, so
-        * we can be sure that sio_ie is
-        * not changing when we read it
-        * along with sio_ir.
-        */
-       spinlock_t is_ir_lock;  /* SIO_IE[SC] mod lock */
-};
-
-/* Local port info for each IOC4 serial ports */
-struct ioc4_port {
-       struct uart_port *ip_port;      /* current active port ptr */
-       /* Ptrs for all ports */
-       struct uart_port *ip_all_ports[UART_PORT_COUNT];
-       /* Back ptrs for this port */
-       struct ioc4_control *ip_control;
-       struct pci_dev *ip_pdev;
-       struct ioc4_soft *ip_ioc4_soft;
-
-       /* pci mem addresses */
-       struct ioc4_misc_regs __iomem *ip_mem;
-       struct ioc4_serial __iomem *ip_serial;
-       struct ioc4_serialregs __iomem *ip_serial_regs;
-       struct ioc4_uartregs __iomem *ip_uart_regs;
-
-       /* Ring buffer page for this port */
-       dma_addr_t ip_dma_ringbuf;
-       /* vaddr of ring buffer */
-       struct ring_buffer *ip_cpu_ringbuf;
-
-       /* Rings for this port */
-       struct ring *ip_inring;
-       struct ring *ip_outring;
-
-       /* Hook to port specific values */
-       struct hooks *ip_hooks;
-
-       spinlock_t ip_lock;
-
-       /* Various rx/tx parameters */
-       int ip_baud;
-       int ip_tx_lowat;
-       int ip_rx_timeout;
-
-       /* Copy of notification bits */
-       int ip_notify;
-
-       /* Shadow copies of various registers so we don't need to PIO
-        * read them constantly
-        */
-       uint32_t ip_ienb;       /* Enabled interrupts */
-       uint32_t ip_sscr;
-       uint32_t ip_tx_prod;
-       uint32_t ip_rx_cons;
-       int ip_pci_bus_speed;
-       unsigned char ip_flags;
-};
-
-/* tx low water mark.  We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY      1000
-#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH     0x01
-#define DCD_ON         0x02
-#define LOWAT_WRITTEN  0x04
-#define READ_ABORTED   0x08
-#define PORT_ACTIVE    0x10
-#define PORT_INACTIVE  0       /* This is the value when "off" */
-
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct hooks {
-       uint32_t intr_delta_dcd;
-       uint32_t intr_delta_cts;
-       uint32_t intr_tx_mt;
-       uint32_t intr_rx_timer;
-       uint32_t intr_rx_high;
-       uint32_t intr_tx_explicit;
-       uint32_t intr_dma_error;
-       uint32_t intr_clear;
-       uint32_t intr_all;
-       int rs422_select_pin;
-};
-
-static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
-       /* Values for port 0 */
-       {
-        IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
-        IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
-        IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
-        IOC4_OTHER_IR_S0_MEMERR,
-        (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
-         IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
-         IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
-         IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
-        IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
-        },
-
-       /* Values for port 1 */
-       {
-        IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
-        IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
-        IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
-        IOC4_OTHER_IR_S1_MEMERR,
-        (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
-         IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
-         IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
-         IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
-        IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
-        },
-
-       /* Values for port 2 */
-       {
-        IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
-        IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
-        IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
-        IOC4_OTHER_IR_S2_MEMERR,
-        (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
-         IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
-         IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
-         IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
-        IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
-        },
-
-       /* Values for port 3 */
-       {
-        IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
-        IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
-        IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
-        IOC4_OTHER_IR_S3_MEMERR,
-        (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
-         IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
-         IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
-         IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
-        IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
-        }
-};
-
-/* A ring buffer entry */
-struct ring_entry {
-       union {
-               struct {
-                       uint32_t alldata;
-                       uint32_t allsc;
-               } all;
-               struct {
-                       char data[4];   /* data bytes */
-                       char sc[4];     /* status/control */
-               } s;
-       } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
-       ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc     u.s.sc
-#define ring_data   u.s.data
-#define ring_allsc  u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
-       struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
-       struct ring TX_0_OR_2;
-       struct ring RX_0_OR_2;
-       struct ring TX_1_OR_3;
-       struct ring RX_1_OR_3;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* Infinite loop detection.
- */
-#define MAXITER 10000000
-
-/* Prototypes */
-static void receive_chars(struct uart_port *);
-static void handle_intr(void *arg, uint32_t sio_ir);
-
-/*
- * port_is_active - determines if this port is currently active
- * @port: ptr to soft struct for this port
- * @uart_port: uart port to test for
- */
-static inline int port_is_active(struct ioc4_port *port,
-               struct uart_port *uart_port)
-{
-       if (port) {
-               if ((port->ip_flags & PORT_ACTIVE)
-                                       && (port->ip_port == uart_port))
-                       return 1;
-       }
-       return 0;
-}
-
-
-/**
- * write_ireg - write the interrupt regs
- * @ioc4_soft: ptr to soft struct for this port
- * @val: value to write
- * @which: which register
- * @type: which ireg set
- */
-static inline void
-write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->sio_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->sio_iec.raw);
-                       break;
-               }
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               switch (which) {
-               case IOC4_W_IES:
-                       writel(val, &mem->other_ies.raw);
-                       break;
-
-               case IOC4_W_IEC:
-                       writel(val, &mem->other_iec.raw);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
-}
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc4_port *port, int baud)
-{
-       int actual_baud;
-       int diff;
-       int lcr;
-       unsigned short divisor;
-       struct ioc4_uartregs __iomem *uart;
-
-       divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
-       if (!divisor)
-               return 1;
-       actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
-
-       diff = actual_baud - baud;
-       if (diff < 0)
-               diff = -diff;
-
-       /* If we're within 1%, we've found a match */
-       if (diff * 100 > actual_baud)
-               return 1;
-
-       uart = port->ip_uart_regs;
-       lcr = readb(&uart->i4u_lcr);
-       writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
-       writeb((unsigned char)divisor, &uart->i4u_dll);
-       writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
-       writeb(lcr, &uart->i4u_lcr);
-       return 0;
-}
-
-
-/**
- * get_ioc4_port - given a uart port, return the control structure
- * @port: uart port
- * @set: set this port as current
- */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
-{
-       struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       struct ioc4_port *port;
-       int port_num, port_type;
-
-       if (control) {
-               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
-                                                       port_num++ ) {
-                       port = control->ic_port[port_num].icp_port;
-                       if (!port)
-                               continue;
-                       for (port_type = UART_PORT_MIN;
-                                               port_type < UART_PORT_COUNT;
-                                               port_type++) {
-                               if (the_port == port->ip_all_ports
-                                                       [port_type]) {
-                                       /* set local copy */
-                                       if (set) {
-                                               port->ip_port = the_port;
-                                       }
-                                       return port;
-                               }
-                       }
-               }
-       }
-       return NULL;
-}
-
-/* The IOC4 hardware provides no atomic way to determine if interrupts
- * are pending since two reads are required to do so.  The handler must
- * read the SIO_IR and the SIO_IES, and take the logical and of the
- * two.  When this value is zero, all interrupts have been serviced and
- * the handler may return.
- *
- * This has the unfortunate "hole" that, if some other CPU or
- * some other thread or some higher level interrupt manages to
- * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
- * think we have observed SIO_IR&SIO_IE==0 when in fact this
- * condition never really occurred.
- *
- * To solve this, we use a simple spinlock that must be held
- * whenever modifying SIO_IE; holding this lock while observing
- * both SIO_IR and SIO_IE guarantees that we do not falsely
- * conclude that no enabled interrupts are pending.
- */
-
-static inline uint32_t
-pending_intrs(struct ioc4_soft *soft, int type)
-{
-       struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-       unsigned long flag;
-       uint32_t intrs = 0;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       spin_lock_irqsave(&soft->is_ir_lock, flag);
-
-       switch (type) {
-       case IOC4_SIO_INTR_TYPE:
-               intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
-               break;
-
-       case IOC4_OTHER_INTR_TYPE:
-               intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
-
-               /* Don't process any ATA interrupte */
-               intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               break;
-
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       return intrs;
-}
-
-/**
- * port_init - Initialize the sio and ioc4 hardware for a given port
- *                     called per port from attach...
- * @port: port to initialize
- */
-static inline int port_init(struct ioc4_port *port)
-{
-       uint32_t sio_cr;
-       struct hooks *hooks = port->ip_hooks;
-       struct ioc4_uartregs __iomem *uart;
-
-       /* Idle the IOC4 serial interface */
-       writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
-
-       /* Wait until any pending bus activity for this port has ceased */
-       do
-               sio_cr = readl(&port->ip_mem->sio_cr.raw);
-       while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
-
-       /* Finish reset sequence */
-       writel(0, &port->ip_serial_regs->sscr);
-
-       /* Once RESET is done, reload cached tx_prod and rx_cons values
-        * and set rings to empty by making prod == cons
-        */
-       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
-       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       /* Disable interrupts for this 16550 */
-       uart = port->ip_uart_regs;
-       writeb(0, &uart->i4u_lcr);
-       writeb(0, &uart->i4u_ier);
-
-       /* Set the default baud */
-       set_baud(port, port->ip_baud);
-
-       /* Set line control to 8 bits no parity */
-       writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Enable the FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
-       /* then reset 16550 FIFOs */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
-                       &uart->i4u_fcr);
-
-       /* Clear modem control register */
-       writeb(0, &uart->i4u_mcr);
-
-       /* Clear deltas in modem status register */
-       readb(&uart->i4u_msr);
-
-       /* Only do this once per port pair */
-       if (port->ip_hooks == &hooks_array[0]
-                           || port->ip_hooks == &hooks_array[2]) {
-               unsigned long ring_pci_addr;
-               uint32_t __iomem *sbbr_l;
-               uint32_t __iomem *sbbr_h;
-
-               if (port->ip_hooks == &hooks_array[0]) {
-                       sbbr_l = &port->ip_serial->sbbr01_l;
-                       sbbr_h = &port->ip_serial->sbbr01_h;
-               } else {
-                       sbbr_l = &port->ip_serial->sbbr23_l;
-                       sbbr_h = &port->ip_serial->sbbr23_h;
-               }
-
-               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
-               DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
-                                       __func__, ring_pci_addr));
-
-               writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
-               writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
-       }
-
-       /* Set the receive timeout value to 10 msec */
-       writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
-       /* Set rx threshold, enable DMA */
-       /* Set high water mark at 3/4 of full ring */
-       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Disable and clear all serial related interrupt bits */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
-                      IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       port->ip_ienb &= ~hooks->intr_clear;
-       writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
-       return 0;
-}
-
-/**
- * handle_dma_error_intr - service any pending DMA error interrupts for the
- *                     given port - 2nd level called via sd_intr
- * @arg: handler arg
- * @other_ir: ioc4regs
- */
-static void handle_dma_error_intr(void *arg, uint32_t other_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       /* ACK the interrupt */
-       writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
-
-       if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
-               printk(KERN_ERR
-                       "PCI error address is 0x%llx, "
-                               "master is serial port %c %s\n",
-                    (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
-                                                        << 32)
-                               | readl(&port->ip_mem->pci_err_addr_l.raw))
-                                       & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
-                    ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
-                            IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
-                    (readl(&port->ip_mem->pci_err_addr_l.raw)
-                               & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
-                               ? "RX" : "TX");
-
-               if (readl(&port->ip_mem->pci_err_addr_l.raw)
-                                               & IOC4_PCI_ERR_ADDR_MUL_ERR) {
-                       printk(KERN_ERR
-                               "Multiple errors occurred\n");
-               }
-       }
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable DMA error interrupts */
-       write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
-                                               IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * intr_connect - interrupt connect function
- * @soft: soft struct for this card
- * @type: interrupt type
- * @intrbits: bit pattern to set
- * @intr: handler function
- * @info: handler arg
- */
-static void
-intr_connect(struct ioc4_soft *soft, int type,
-                 uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
-{
-       int i;
-       struct ioc4_intr_info *intr_ptr;
-
-       BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
-              || (type == IOC4_OTHER_INTR_TYPE)));
-
-       i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
-       BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
-
-       /* Save off the lower level interrupt handler */
-       intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
-       intr_ptr->sd_bits = intrbits;
-       intr_ptr->sd_intr = intr;
-       intr_ptr->sd_info = info;
-}
-
-/**
- * ioc4_intr - Top level IOC4 interrupt handler.
- * @irq: irq value
- * @arg: handler arg
- */
-
-static irqreturn_t ioc4_intr(int irq, void *arg)
-{
-       struct ioc4_soft *soft;
-       uint32_t this_ir, this_mir;
-       int xx, num_intrs = 0;
-       int intr_type;
-       int handled = 0;
-       struct ioc4_intr_info *intr_info;
-
-       soft = arg;
-       for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
-               num_intrs = (int)atomic_read(
-                               &soft->is_intr_type[intr_type].is_num_intrs);
-
-               this_mir = this_ir = pending_intrs(soft, intr_type);
-
-               /* Farm out the interrupt to the various drivers depending on
-                * which interrupt bits are set.
-                */
-               for (xx = 0; xx < num_intrs; xx++) {
-                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
-                       this_mir = this_ir & intr_info->sd_bits;
-                       if (this_mir) {
-                               /* Disable owned interrupts, call handler */
-                               handled++;
-                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
-                                                               intr_type);
-                               intr_info->sd_intr(intr_info->sd_info, this_mir);
-                               this_ir &= ~this_mir;
-                       }
-               }
-       }
-#ifdef DEBUG_INTERRUPTS
-       {
-               struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-               unsigned long flag;
-
-               spin_lock_irqsave(&soft->is_ir_lock, flag);
-               printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
-                               "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
-                    __func__, __LINE__,
-                    (void *)mem, readl(&mem->sio_ir.raw),
-                    readl(&mem->sio_ies.raw),
-                    readl(&mem->other_ir.raw),
-                    readl(&mem->other_ies.raw),
-                    IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
-               spin_unlock_irqrestore(&soft->is_ir_lock, flag);
-       }
-#endif
-       return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/**
- * ioc4_attach_local - Device initialization.
- *                     Called at *_attach() time for each
- *                     IOC4 with serial ports in the system.
- * @idd: Master module data for this IOC4
- */
-static inline int ioc4_attach_local(struct ioc4_driver_data *idd)
-{
-       struct ioc4_port *port;
-       struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
-       int port_number;
-       uint16_t ioc4_revid_min = 62;
-       uint16_t ioc4_revid;
-       struct pci_dev *pdev = idd->idd_pdev;
-       struct ioc4_control* control = idd->idd_serial_data;
-       struct ioc4_soft *soft = control->ic_soft;
-       void __iomem *ioc4_misc = idd->idd_misc_regs;
-       void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
-
-       /* IOC4 firmware must be at least rev 62 */
-       pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
-
-       printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
-       if (ioc4_revid < ioc4_revid_min) {
-               printk(KERN_WARNING
-                   "IOC4 serial not supported on firmware rev %d, "
-                               "please upgrade to rev %d or higher\n",
-                               ioc4_revid, ioc4_revid_min);
-               return -EPERM;
-       }
-       BUG_ON(ioc4_misc == NULL);
-       BUG_ON(ioc4_serial == NULL);
-
-       /* Create port structures for each port */
-       for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
-                                                       port_number++) {
-               port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
-               if (!port) {
-                       printk(KERN_WARNING
-                               "IOC4 serial memory not available for port\n");
-                       goto free;
-               }
-               spin_lock_init(&port->ip_lock);
-
-               /* we need to remember the previous ones, to point back to
-                * them farther down - setting up the ring buffers.
-                */
-               ports[port_number] = port;
-
-               /* Allocate buffers and jumpstart the hardware.  */
-               control->ic_port[port_number].icp_port = port;
-               port->ip_ioc4_soft = soft;
-               port->ip_pdev = pdev;
-               port->ip_ienb = 0;
-               /* Use baud rate calculations based on detected PCI
-                * bus speed.  Simply test whether the PCI clock is
-                * running closer to 66MHz or 33MHz.
-                */
-               if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
-               } else {
-                       port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
-               }
-               port->ip_baud = 9600;
-               port->ip_control = control;
-               port->ip_mem = ioc4_misc;
-               port->ip_serial = ioc4_serial;
-
-               /* point to the right hook */
-               port->ip_hooks = &hooks_array[port_number];
-
-               /* Get direct hooks to the serial regs and uart regs
-                * for this port
-                */
-               switch (port_number) {
-               case 0:
-                       port->ip_serial_regs = &(port->ip_serial->port_0);
-                       port->ip_uart_regs = &(port->ip_serial->uart_0);
-                       break;
-               case 1:
-                       port->ip_serial_regs = &(port->ip_serial->port_1);
-                       port->ip_uart_regs = &(port->ip_serial->uart_1);
-                       break;
-               case 2:
-                       port->ip_serial_regs = &(port->ip_serial->port_2);
-                       port->ip_uart_regs = &(port->ip_serial->uart_2);
-                       break;
-               default:
-               case 3:
-                       port->ip_serial_regs = &(port->ip_serial->port_3);
-                       port->ip_uart_regs = &(port->ip_serial->uart_3);
-                       break;
-               }
-
-               /* ring buffers are 1 to a pair of ports */
-               if (port_number && (port_number & 1)) {
-                       /* odd use the evens buffer */
-                       port->ip_dma_ringbuf =
-                                       ports[port_number - 1]->ip_dma_ringbuf;
-                       port->ip_cpu_ringbuf =
-                                       ports[port_number - 1]->ip_cpu_ringbuf;
-                       port->ip_inring = RING(port, RX_1_OR_3);
-                       port->ip_outring = RING(port, TX_1_OR_3);
-
-               } else {
-                       if (port->ip_dma_ringbuf == 0) {
-                               port->ip_cpu_ringbuf = pci_alloc_consistent
-                                       (pdev, TOTAL_RING_BUF_SIZE,
-                                       &port->ip_dma_ringbuf);
-
-                       }
-                       BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
-                               (TOTAL_RING_BUF_SIZE - 1)) == 0));
-                       DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
-                                               "ip_dma_ringbuf 0x%p\n",
-                                       __func__,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       (void *)port->ip_dma_ringbuf));
-                       port->ip_inring = RING(port, RX_0_OR_2);
-                       port->ip_outring = RING(port, TX_0_OR_2);
-               }
-               DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
-                               __func__,
-                               port_number, (void *)port, (void *)control));
-               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
-                               (void *)port->ip_serial_regs,
-                               (void *)port->ip_uart_regs));
-
-               /* Initialize the hardware for IOC4 */
-               port_init(port);
-
-               DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
-                                               "outring 0x%p\n",
-                               __func__,
-                               port_number, (void *)port,
-                               (void *)port->ip_inring,
-                               (void *)port->ip_outring));
-
-               /* Attach interrupt handlers */
-               intr_connect(soft, IOC4_SIO_INTR_TYPE,
-                               GET_SIO_IR(port_number),
-                               handle_intr, port);
-
-               intr_connect(soft, IOC4_OTHER_INTR_TYPE,
-                               GET_OTHER_IR(port_number),
-                               handle_dma_error_intr, port);
-       }
-       return 0;
-
-free:
-       while (port_number)
-               kfree(ports[--port_number]);
-       return -ENOMEM;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if ((port->ip_ienb & mask) != mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
-                                               IOC4_SIO_INTR_TYPE);
-               port->ip_ienb |= mask;
-       }
-
-       if (port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc4_port *port)
-{
-       int spiniter = 0;
-
-       port->ip_flags = PORT_ACTIVE;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs-> sscr)
-                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER) {
-                               port->ip_flags = PORT_INACTIVE;
-                               return -1;
-                       }
-               }
-       }
-
-       /* Reset the input fifo.  If the uart received chars while the port
-        * was closed and DMA is not enabled, the uart may have a bunch of
-        * chars hanging around in its rx fifo which will not be discarded
-        * by rclr in the upper layer. We must get rid of them here.
-        */
-       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
-                               &port->ip_uart_regs->i4u_fcr);
-
-       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
-                                       /* UART_LCR_STOP == 1 stop */
-
-       /* Re-enable DMA, set default threshold to intr whenever there is
-        * data available.
-        */
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= 1;     /* default threshold */
-
-       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
-        * flag if it was set above
-        */
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       port->ip_tx_lowat = 1;
-       return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
-{
-       int threshold;
-
-       port->ip_rx_timeout = timeout;
-
-       /* Timeout is in ticks.  Let's figure out how many chars we
-        * can receive at the current baud rate in that interval
-        * and set the rx threshold to that amount.  There are 4 chars
-        * per ring entry, so we'll divide the number of chars that will
-        * arrive in timeout by 4.
-        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
-        */
-       threshold = timeout * port->ip_baud / 4000;
-       if (threshold == 0)
-               threshold = 1;  /* otherwise we'll intr all the time! */
-
-       if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
-               return 1;
-
-       port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
-       port->ip_sscr |= threshold;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Now set the rx timeout to the given value
-        * again timeout * IOC4_SRTR_HZ / HZ
-        */
-       timeout = timeout * IOC4_SRTR_HZ / 100;
-       if (timeout > IOC4_SRTR_CNT)
-               timeout = IOC4_SRTR_CNT;
-
-       writel(timeout, &port->ip_serial_regs->srtr);
-       return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc4_port *port,
-           int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
-       char lcr, sizebits;
-       int spiniter = 0;
-
-       DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
-               __func__, baud, byte_size, stop_bits, parenb, parodd));
-
-       if (set_baud(port, baud))
-               return 1;
-
-       switch (byte_size) {
-       case 5:
-               sizebits = UART_LCR_WLEN5;
-               break;
-       case 6:
-               sizebits = UART_LCR_WLEN6;
-               break;
-       case 7:
-               sizebits = UART_LCR_WLEN7;
-               break;
-       case 8:
-               sizebits = UART_LCR_WLEN8;
-               break;
-       default:
-               return 1;
-       }
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while((readl(&port->ip_serial_regs->sscr)
-                                               & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-
-       /* Clear relevant fields in lcr */
-       lcr = readb(&port->ip_uart_regs->i4u_lcr);
-       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
-                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
-       /* Set byte size in lcr */
-       lcr |= sizebits;
-
-       /* Set parity */
-       if (parenb) {
-               lcr |= UART_LCR_PARITY;
-               if (!parodd)
-                       lcr |= UART_LCR_EPAR;
-       }
-
-       /* Set stop bits */
-       if (stop_bits)
-               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
-       writeb(lcr, &port->ip_uart_regs->i4u_lcr);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       port->ip_baud = baud;
-
-       /* When we get within this number of ring entries of filling the
-        * entire ring on tx, place an EXPLICIT intr to generate a lowat
-        * notification when output has drained.
-        */
-       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
-       if (port->ip_tx_lowat == 0)
-               port->ip_tx_lowat = 1;
-
-       set_rx_timeout(port, 2);
-
-       return 0;
-}
-
-/**
- * do_write - Write bytes to the port.  Returns the number of bytes
- *                     actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc4_port *port, char *buf, int len)
-{
-       int prod_ptr, cons_ptr, total = 0;
-       struct ring *outring;
-       struct ring_entry *entry;
-       struct hooks *hooks = port->ip_hooks;
-
-       BUG_ON(!(len >= 0));
-
-       prod_ptr = port->ip_tx_prod;
-       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
-       outring = port->ip_outring;
-
-       /* Maintain a 1-entry red-zone.  The ring buffer is full when
-        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
-        * in the body of the loop, I'll do it now.
-        */
-       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
-       /* Stuff the bytes into the output */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               int xx;
-
-               /* Get 4 bytes (one ring entry) at a time */
-               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
-               /* Invalidate all entries */
-               entry->ring_allsc = 0;
-
-               /* Copy in some bytes */
-               for (xx = 0; (xx < 4) && (len > 0); xx++) {
-                       entry->ring_data[xx] = *buf++;
-                       entry->ring_sc[xx] = IOC4_TXCB_VALID;
-                       len--;
-                       total++;
-               }
-
-               /* If we are within some small threshold of filling up the
-                * entire ring buffer, we must place an EXPLICIT intr here
-                * to generate a lowat interrupt in case we subsequently
-                * really do fill up the ring and the caller goes to sleep.
-                * No need to place more than one though.
-                */
-               if (!(port->ip_flags & LOWAT_WRITTEN) &&
-                       ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
-                               <= port->ip_tx_lowat
-                                       * (int)sizeof(struct ring_entry)) {
-                       port->ip_flags |= LOWAT_WRITTEN;
-                       entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
-               }
-
-               /* Go on to next entry */
-               prod_ptr += sizeof(struct ring_entry);
-               prod_ptr &= PROD_CONS_MASK;
-       }
-
-       /* If we sent something, start DMA if necessary */
-       if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-
-       /* Store the new producer pointer.  If tx is disabled, we stuff the
-        * data into the ring buffer, but we don't actually start tx.
-        */
-       if (!uart_tx_stopped(port->ip_port)) {
-               writel(prod_ptr, &port->ip_serial_regs->stpir);
-
-               /* If we are now transmitting, enable tx_mt interrupt so we
-                * can disable DMA if necessary when the tx finishes.
-                */
-               if (total > 0)
-                       enable_intrs(port, hooks->intr_tx_mt);
-       }
-       port->ip_tx_prod = prod_ptr;
-       return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void disable_intrs(struct ioc4_port *port, uint32_t mask)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       if (port->ip_ienb & mask) {
-               write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
-                                       IOC4_SIO_INTR_TYPE);
-               port->ip_ienb &= ~mask;
-       }
-
-       if (!port->ip_ienb)
-               write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
-                               IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc4_port *port, int mask, int set_on)
-{
-       struct hooks *hooks = port->ip_hooks;
-       uint32_t intrbits, sscrbits;
-
-       BUG_ON(!mask);
-
-       intrbits = sscrbits = 0;
-
-       if (mask & N_DATA_READY)
-               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
-       if (mask & N_OUTPUT_LOWAT)
-               intrbits |= hooks->intr_tx_explicit;
-       if (mask & N_DDCD) {
-               intrbits |= hooks->intr_delta_dcd;
-               sscrbits |= IOC4_SSCR_RX_RING_DCD;
-       }
-       if (mask & N_DCTS)
-               intrbits |= hooks->intr_delta_cts;
-
-       if (set_on) {
-               enable_intrs(port, intrbits);
-               port->ip_notify |= mask;
-               port->ip_sscr |= sscrbits;
-       } else {
-               disable_intrs(port, intrbits);
-               port->ip_notify &= ~mask;
-               port->ip_sscr &= ~sscrbits;
-       }
-
-       /* We require DMA if either DATA_READY or DDCD notification is
-        * currently requested. If neither of these is requested and
-        * there is currently no tx in progress, DMA may be disabled.
-        */
-       if (port->ip_notify & (N_DATA_READY | N_DDCD))
-               port->ip_sscr |= IOC4_SSCR_DMA_EN;
-       else if (!(port->ip_ienb & hooks->intr_tx_mt))
-               port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
-               int mask1, int mask2)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       int spiniter = 0;
-       char mcr;
-
-       if (!port)
-               return -1;
-
-       /* Pause the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
-                       &port->ip_serial_regs->sscr);
-               while ((readl(&port->ip_serial_regs->sscr)
-                                       & IOC4_SSCR_PAUSE_STATE) == 0) {
-                       spiniter++;
-                       if (spiniter > MAXITER)
-                               return -1;
-               }
-       }
-       shadow = readl(&port->ip_serial_regs->shadow);
-       mcr = (shadow & 0xff000000) >> 24;
-
-       /* Set new value */
-       mcr |= mask1;
-       shadow |= mask2;
-
-       writeb(mcr, &port->ip_uart_regs->i4u_mcr);
-       writel(shadow, &port->ip_serial_regs->shadow);
-
-       /* Re-enable the DMA interface if necessary */
-       if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
-               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-       }
-       return 0;
-}
-
-/**
- * ioc4_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc4_set_proto(struct ioc4_port *port, int proto)
-{
-       struct hooks *hooks = port->ip_hooks;
-
-       switch (proto) {
-       case PROTO_RS232:
-               /* Clear the appropriate GIO pin */
-               writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       case PROTO_RS422:
-               /* Set the appropriate GIO pin */
-               writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
-               break;
-
-       default:
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with ip_lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
-       int xmit_count, tail, head;
-       int result;
-       char *start;
-       struct tty_struct *tty;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct uart_state *state;
-
-       if (!the_port)
-               return;
-       if (!port)
-               return;
-
-       state = the_port->state;
-       tty = state->port.tty;
-
-       if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
-               /* Nothing to do or hw stopped */
-               set_notification(port, N_ALL_OUTPUT, 0);
-               return;
-       }
-
-       head = state->xmit.head;
-       tail = state->xmit.tail;
-       start = (char *)&state->xmit.buf[tail];
-
-       /* write out all the data or until the end of the buffer */
-       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
-       if (xmit_count > 0) {
-               result = do_write(port, start, xmit_count);
-               if (result > 0) {
-                       /* booking */
-                       xmit_count -= result;
-                       the_port->icount.tx += result;
-                       /* advance the pointers */
-                       tail += result;
-                       tail &= UART_XMIT_SIZE - 1;
-                       state->xmit.tail = tail;
-                       start = (char *)&state->xmit.buf[tail];
-               }
-       }
-       if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(the_port);
-
-       if (uart_circ_empty(&state->xmit)) {
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-       } else {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-       }
-}
-
-/**
- * ioc4_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc4_change_speed(struct uart_port *the_port,
-                 struct ktermios *new_termios, struct ktermios *old_termios)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       int baud, bits;
-       unsigned cflag, iflag;
-       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
-       struct uart_state *state = the_port->state;
-
-       cflag = new_termios->c_cflag;
-       iflag = new_termios->c_iflag;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               new_data = 5;
-               bits = 7;
-               break;
-       case CS6:
-               new_data = 6;
-               bits = 8;
-               break;
-       case CS7:
-               new_data = 7;
-               bits = 9;
-               break;
-       case CS8:
-               new_data = 8;
-               bits = 10;
-               break;
-       default:
-               /* cuz we always need a default ... */
-               new_data = 5;
-               bits = 7;
-               break;
-       }
-       if (cflag & CSTOPB) {
-               bits++;
-               new_stop = 1;
-       }
-       if (cflag & PARENB) {
-               bits++;
-               new_parity_enable = 1;
-               if (cflag & PARODD)
-                       new_parity = 1;
-       }
-       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
-                               MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
-       DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
-
-       /* default is 9600 */
-       if (!baud)
-               baud = 9600;
-
-       if (!the_port->fifosize)
-               the_port->fifosize = IOC4_FIFO_CHARS;
-       the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
-       the_port->timeout += HZ / 50;   /* Add .02 seconds of slop */
-
-       the_port->ignore_status_mask = N_ALL_INPUT;
-
-       state->port.low_latency = 1;
-
-       if (iflag & IGNPAR)
-               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
-                                               | N_FRAMING_ERROR);
-       if (iflag & IGNBRK) {
-               the_port->ignore_status_mask &= ~N_BREAK;
-               if (iflag & IGNPAR)
-                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
-       }
-       if (!(cflag & CREAD)) {
-               /* ignore everything */
-               the_port->ignore_status_mask &= ~N_DATA_READY;
-       }
-
-       if (cflag & CRTSCTS) {
-               port->ip_sscr |= IOC4_SSCR_HFC_EN;
-       }
-       else {
-               port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
-       }
-       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
-       /* Set the configuration and proper notification call */
-       DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
-               "config_port(baud %d data %d stop %d p enable %d parity %d),"
-               " notification 0x%x\n",
-            __func__, (void *)port, cflag, baud, new_data, new_stop,
-            new_parity_enable, new_parity, the_port->ignore_status_mask));
-
-       if ((config_port(port, baud,            /* baud */
-                        new_data,              /* byte size */
-                        new_stop,              /* stop bits */
-                        new_parity_enable,     /* set parity */
-                        new_parity)) >= 0) {   /* parity 1==odd */
-               set_notification(port, the_port->ignore_status_mask, 1);
-       }
-}
-
-/**
- * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic4_startup_local(struct uart_port *the_port)
-{
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       if (!the_port)
-               return -1;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return -1;
-
-       state = the_port->state;
-
-       local_open(port);
-
-       /* set the protocol - mapbase has the port type */
-       ioc4_set_proto(port, the_port->mapbase);
-
-       /* set the speed of the serial port */
-       ioc4_change_speed(the_port, &state->port.tty->termios,
-                         (struct ktermios *)0);
-
-       return 0;
-}
-
-/*
- * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @the_port: port to output
- */
-static void ioc4_cb_output_lowat(struct uart_port *the_port)
-{
-       unsigned long pflags;
-
-       /* ip_lock is set on the call here */
-       if (the_port) {
-               spin_lock_irqsave(&the_port->lock, pflags);
-               transmit_chars(the_port);
-               spin_unlock_irqrestore(&the_port->lock, pflags);
-       }
-}
-
-/**
- * handle_intr - service any interrupts for the given port - 2nd level
- *                     called via sd_intr
- * @arg: handler arg
- * @sio_ir: ioc4regs
- */
-static void handle_intr(void *arg, uint32_t sio_ir)
-{
-       struct ioc4_port *port = (struct ioc4_port *)arg;
-       struct hooks *hooks = port->ip_hooks;
-       unsigned int rx_high_rd_aborted = 0;
-       unsigned long flags;
-       struct uart_port *the_port;
-       int loop_counter;
-
-       /* Possible race condition here: The tx_mt interrupt bit may be
-        * cleared without the intervention of the interrupt handler,
-        * e.g. by a write.  If the top level interrupt handler reads a
-        * tx_mt, then some other processor does a write, starting up
-        * output, then we come in here, see the tx_mt and stop DMA, the
-        * output started by the other processor will hang.  Thus we can
-        * only rely on tx_mt being legitimate if it is read while the
-        * port lock is held.  Therefore this bit must be ignored in the
-        * passed in interrupt mask which was read by the top level
-        * interrupt handler since the port lock was not held at the time
-        * it was read.  We can only rely on this bit being accurate if it
-        * is read while the port lock is held.  So we'll clear it for now,
-        * and reload it later once we have the port lock.
-        */
-       sio_ir &= ~(hooks->intr_tx_mt);
-
-       spin_lock_irqsave(&port->ip_lock, flags);
-
-       loop_counter = MAXITER; /* to avoid hangs */
-
-       do {
-               uint32_t shadow;
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on interrupt.\n");
-                       break;
-               }
-
-               /* Handle a DCD change */
-               if (sio_ir & hooks->intr_delta_dcd) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_dcd,
-                               &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DDCD)
-                                       && (shadow & IOC4_SHADOW_DCD)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.dcd = 1;
-                               wake_up_interruptible
-                                           (&the_port->state->port.delta_msr_wait);
-                       } else if ((port->ip_notify & N_DDCD)
-                                       && !(shadow & IOC4_SHADOW_DCD)) {
-                               /* Flag delta DCD/no DCD */
-                               port->ip_flags |= DCD_ON;
-                       }
-               }
-
-               /* Handle a CTS change */
-               if (sio_ir & hooks->intr_delta_cts) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_delta_cts,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       shadow = readl(&port->ip_serial_regs->shadow);
-
-                       if ((port->ip_notify & N_DCTS)
-                                       && (port->ip_port)) {
-                               the_port = port->ip_port;
-                               the_port->icount.cts =
-                                       (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
-                               wake_up_interruptible
-                                       (&the_port->state->port.delta_msr_wait);
-                       }
-               }
-
-               /* rx timeout interrupt.  Must be some data available.  Put this
-                * before the check for rx_high since servicing this condition
-                * may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_rx_timer) {
-                       /* ACK the interrupt */
-                       writel(hooks->intr_rx_timer,
-                               &port->ip_mem->sio_ir.raw);
-
-                       if ((port->ip_notify & N_DATA_READY)
-                                       && (port->ip_port)) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-               }
-
-               /* rx high interrupt. Must be after rx_timer.  */
-               else if (sio_ir & hooks->intr_rx_high) {
-                       /* Data available, notify upper layer */
-                       if ((port->ip_notify & N_DATA_READY)
-                                               && port->ip_port) {
-                               /* ip_lock is set on call here */
-                               receive_chars(port->ip_port);
-                       }
-
-                       /* We can't ACK this interrupt.  If receive_chars didn't
-                        * cause the condition to clear, we'll have to disable
-                        * the interrupt until the data is drained.
-                        * If the read was aborted, don't disable the interrupt
-                        * as this may cause us to hang indefinitely.  An
-                        * aborted read generally means that this interrupt
-                        * hasn't been delivered to the cpu yet anyway, even
-                        * though we see it as asserted when we read the sio_ir.
-                        */
-                       if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
-                               if ((port->ip_flags & READ_ABORTED) == 0) {
-                                       port->ip_ienb &= ~hooks->intr_rx_high;
-                                       port->ip_flags |= INPUT_HIGH;
-                               } else {
-                                       rx_high_rd_aborted++;
-                               }
-                       }
-               }
-
-               /* We got a low water interrupt: notify upper layer to
-                * send more data.  Must come before tx_mt since servicing
-                * this condition may cause that condition to clear.
-                */
-               if (sio_ir & hooks->intr_tx_explicit) {
-                       port->ip_flags &= ~LOWAT_WRITTEN;
-
-                       /* ACK the interrupt */
-                       writel(hooks->intr_tx_explicit,
-                                       &port->ip_mem->sio_ir.raw);
-
-                       if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc4_cb_output_lowat(port->ip_port);
-               }
-
-               /* Handle tx_mt.  Must come after tx_explicit.  */
-               else if (sio_ir & hooks->intr_tx_mt) {
-                       /* If we are expecting a lowat notification
-                        * and we get to this point it probably means that for
-                        * some reason the tx_explicit didn't work as expected
-                        * (that can legitimately happen if the output buffer is
-                        * filled up in just the right way).
-                        * So send the notification now.
-                        */
-                       if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc4_cb_output_lowat(port->ip_port);
-
-                               /* We need to reload the sio_ir since the lowat
-                                * call may have caused another write to occur,
-                                * clearing the tx_mt condition.
-                                */
-                               sio_ir = PENDING(port);
-                       }
-
-                       /* If the tx_mt condition still persists even after the
-                        * lowat call, we've got some work to do.
-                        */
-                       if (sio_ir & hooks->intr_tx_mt) {
-
-                               /* If we are not currently expecting DMA input,
-                                * and the transmitter has just gone idle,
-                                * there is no longer any reason for DMA, so
-                                * disable it.
-                                */
-                               if (!(port->ip_notify
-                                               & (N_DATA_READY | N_DDCD))) {
-                                       BUG_ON(!(port->ip_sscr
-                                                       & IOC4_SSCR_DMA_EN));
-                                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                                       writel(port->ip_sscr,
-                                          &port->ip_serial_regs->sscr);
-                               }
-
-                               /* Prevent infinite tx_mt interrupt */
-                               port->ip_ienb &= ~hooks->intr_tx_mt;
-                       }
-               }
-               sio_ir = PENDING(port);
-
-               /* if the read was aborted and only hooks->intr_rx_high,
-                * clear hooks->intr_rx_high, so we do not loop forever.
-                */
-
-               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
-                       sio_ir &= ~hooks->intr_rx_high;
-               }
-       } while (sio_ir & hooks->intr_all);
-
-       spin_unlock_irqrestore(&port->ip_lock, flags);
-
-       /* Re-enable interrupts before returning from interrupt handler.
-        * Getting interrupted here is okay.  It'll just v() our semaphore, and
-        * we'll come through the loop again.
-        */
-
-       write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
-                                                       IOC4_SIO_INTR_TYPE);
-}
-
-/*
- * ioc4_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
-       struct uart_icount *icount;
-
-       icount = &the_port->icount;
-
-       if (ncs & NCS_BREAK)
-               icount->brk++;
-       if (ncs & NCS_FRAMING)
-               icount->frame++;
-       if (ncs & NCS_OVERRUN)
-               icount->overrun++;
-       if (ncs & NCS_PARITY)
-               icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port.  Return the number of bytes
- *                     actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, unsigned char *buf,
-                               int len)
-{
-       int prod_ptr, cons_ptr, total;
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       struct ring *inring;
-       struct ring_entry *entry;
-       struct hooks *hooks;
-       int byte_num;
-       char *sc;
-       int loop_counter;
-
-       BUG_ON(!(len >= 0));
-       BUG_ON(!port);
-       hooks = port->ip_hooks;
-
-       /* There is a nasty timing issue in the IOC4. When the rx_timer
-        * expires or the rx_high condition arises, we take an interrupt.
-        * At some point while servicing the interrupt, we read bytes from
-        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
-        * not started until the first byte is received *after* it is armed,
-        * and any bytes pending in the rx construction buffers are not drained
-        * to memory until either there are 4 bytes available or the rx_timer
-        * expires.  This leads to a potential situation where data is left
-        * in the construction buffers forever - 1 to 3 bytes were received
-        * after the interrupt was generated but before the rx_timer was
-        * re-armed. At that point as long as no subsequent bytes are received
-        * the timer will never be started and the bytes will remain in the
-        * construction buffer forever.  The solution is to execute a DRAIN
-        * command after rearming the timer.  This way any bytes received before
-        * the DRAIN will be drained to memory, and any bytes received after
-        * the DRAIN will start the TIMER and be drained when it expires.
-        * Luckily, this only needs to be done when the DMA buffer is empty
-        * since there is no requirement that this function return all
-        * available data as long as it returns some.
-        */
-       /* Re-arm the timer */
-       writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
-       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-       cons_ptr = port->ip_rx_cons;
-
-       if (prod_ptr == cons_ptr) {
-               int reset_dma = 0;
-
-               /* Input buffer appears empty, do a flush. */
-
-               /* DMA must be enabled for this to work. */
-               if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
-                       port->ip_sscr |= IOC4_SSCR_DMA_EN;
-                       reset_dma = 1;
-               }
-
-               /* Potential race condition: we must reload the srpir after
-                * issuing the drain command, otherwise we could think the rx
-                * buffer is empty, then take a very long interrupt, and when
-                * we come back it's full and we wait forever for the drain to
-                * complete.
-                */
-               writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
-                               &port->ip_serial_regs->sscr);
-               prod_ptr = readl(&port->ip_serial_regs->srpir)
-                               & PROD_CONS_MASK;
-
-               /* We must not wait for the DRAIN to complete unless there are
-                * at least 8 bytes (2 ring entries) available to receive the
-                * data otherwise the DRAIN will never complete and we'll
-                * deadlock here.
-                * In fact, to make things easier, I'll just ignore the flush if
-                * there is any data at all now available.
-                */
-               if (prod_ptr == cons_ptr) {
-                       loop_counter = 0;
-                       while (readl(&port->ip_serial_regs->sscr) &
-                                               IOC4_SSCR_RX_DRAIN) {
-                               loop_counter++;
-                               if (loop_counter > MAXITER)
-                                       return -1;
-                       }
-
-                       /* SIGH. We have to reload the prod_ptr *again* since
-                        * the drain may have caused it to change
-                        */
-                       prod_ptr = readl(&port->ip_serial_regs->srpir)
-                                                       & PROD_CONS_MASK;
-               }
-               if (reset_dma) {
-                       port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-               }
-       }
-       inring = port->ip_inring;
-       port->ip_flags &= ~READ_ABORTED;
-
-       total = 0;
-       loop_counter = 0xfffff; /* to avoid hangs */
-
-       /* Grab bytes from the hardware */
-       while ((prod_ptr != cons_ptr) && (len > 0)) {
-               entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
-
-               if ( loop_counter-- <= 0 ) {
-                       printk(KERN_WARNING "IOC4 serial: "
-                                       "possible hang condition/"
-                                       "port stuck on read.\n");
-                       break;
-               }
-
-               /* According to the producer pointer, this ring entry
-                * must contain some data.  But if the PIO happened faster
-                * than the DMA, the data may not be available yet, so let's
-                * wait until it arrives.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       /* Indicate the read is aborted so we don't disable
-                        * the interrupt thinking that the consumer is
-                        * congested.
-                        */
-                       port->ip_flags |= READ_ABORTED;
-                       len = 0;
-                       break;
-               }
-
-               /* Load the bytes/status out of the ring entry */
-               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
-                       sc = &(entry->ring_sc[byte_num]);
-
-                       /* Check for change in modem state or overrun */
-                       if ((*sc & IOC4_RXSB_MODEM_VALID)
-                                               && (port->ip_notify & N_DDCD)) {
-                               /* Notify upper layer if DCD dropped */
-
-                               if ((port->ip_flags & DCD_ON)
-                                               && !(*sc & IOC4_RXSB_DCD)) {
-
-                                       /* If we have already copied some data,
-                                        * return it.  We'll pick up the carrier
-                                        * drop on the next pass.  That way we
-                                        * don't throw away the data that has
-                                        * already been copied back to
-                                        * the caller's buffer.
-                                        */
-                                       if (total > 0) {
-                                               len = 0;
-                                               break;
-                                       }
-                                       port->ip_flags &= ~DCD_ON;
-
-                                       /* Turn off this notification so the
-                                        * carrier drop protocol won't see it
-                                        * again when it does a read.
-                                        */
-                                       *sc &= ~IOC4_RXSB_MODEM_VALID;
-
-                                       /* To keep things consistent, we need
-                                        * to update the consumer pointer so
-                                        * the next reader won't come in and
-                                        * try to read the same ring entries
-                                        * again. This must be done here before
-                                        * the dcd change.
-                                        */
-
-                                       if ((entry->ring_allsc & RING_ANY_VALID)
-                                                                       == 0) {
-                                               cons_ptr += (int)sizeof
-                                                       (struct ring_entry);
-                                               cons_ptr &= PROD_CONS_MASK;
-                                       }
-                                       writel(cons_ptr,
-                                               &port->ip_serial_regs->srcir);
-                                       port->ip_rx_cons = cons_ptr;
-
-                                       /* Notify upper layer of carrier drop */
-                                       if ((port->ip_notify & N_DDCD)
-                                                  && port->ip_port) {
-                                               the_port->icount.dcd = 0;
-                                               wake_up_interruptible
-                                                   (&the_port->state->
-                                                       port.delta_msr_wait);
-                                       }
-
-                                       /* If we had any data to return, we
-                                        * would have returned it above.
-                                        */
-                                       return 0;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_MODEM_VALID) {
-                               /* Notify that an input overrun occurred */
-                               if ((*sc & IOC4_RXSB_OVERRUN)
-                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
-                                       ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
-                               }
-                               /* Don't look at this byte again */
-                               *sc &= ~IOC4_RXSB_MODEM_VALID;
-                       }
-
-                       /* Check for valid data or RX errors */
-                       if ((*sc & IOC4_RXSB_DATA_VALID) &&
-                                       ((*sc & (IOC4_RXSB_PAR_ERR
-                                                       | IOC4_RXSB_FRAME_ERR
-                                                       | IOC4_RXSB_BREAK))
-                                       && (port->ip_notify & (N_PARITY_ERROR
-                                                       | N_FRAMING_ERROR
-                                                       | N_BREAK)))) {
-                               /* There is an error condition on the next byte.
-                                * If we have already transferred some bytes,
-                                * we'll stop here. Otherwise if this is the
-                                * first byte to be read, we'll just transfer
-                                * it alone after notifying the
-                                * upper layer of its status.
-                                */
-                               if (total > 0) {
-                                       len = 0;
-                                       break;
-                               } else {
-                                       if ((*sc & IOC4_RXSB_PAR_ERR) &&
-                                          (port->ip_notify & N_PARITY_ERROR)) {
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_PARITY);
-                                       }
-                                       if ((*sc & IOC4_RXSB_FRAME_ERR) &&
-                                          (port->ip_notify & N_FRAMING_ERROR)){
-                                               ioc4_cb_post_ncs(the_port,
-                                                               NCS_FRAMING);
-                                       }
-                                       if ((*sc & IOC4_RXSB_BREAK)
-                                           && (port->ip_notify & N_BREAK)) {
-                                                       ioc4_cb_post_ncs
-                                                                   (the_port,
-                                                                    NCS_BREAK);
-                                       }
-                                       len = 1;
-                               }
-                       }
-                       if (*sc & IOC4_RXSB_DATA_VALID) {
-                               *sc &= ~IOC4_RXSB_DATA_VALID;
-                               *buf = entry->ring_data[byte_num];
-                               buf++;
-                               len--;
-                               total++;
-                       }
-               }
-
-               /* If we used up this entry entirely, go on to the next one,
-                * otherwise we must have run out of buffer space, so
-                * leave the consumer pointer here for the next read in case
-                * there are still unread bytes in this entry.
-                */
-               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
-                       cons_ptr += (int)sizeof(struct ring_entry);
-                       cons_ptr &= PROD_CONS_MASK;
-               }
-       }
-
-       /* Update consumer pointer and re-arm rx timer interrupt */
-       writel(cons_ptr, &port->ip_serial_regs->srcir);
-       port->ip_rx_cons = cons_ptr;
-
-       /* If we have now dipped below the rx high water mark and we have
-        * rx_high interrupt turned off, we can now turn it back on again.
-        */
-       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
-                       & PROD_CONS_MASK) < ((port->ip_sscr &
-                               IOC4_SSCR_RX_THRESHOLD)
-                                       << IOC4_PROD_CONS_PTR_OFF))) {
-               port->ip_flags &= ~INPUT_HIGH;
-               enable_intrs(port, hooks->intr_rx_high);
-       }
-       return total;
-}
-
-/**
- * receive_chars - upper level read. Called with ip_lock.
- * @the_port: port to read from
- */
-static void receive_chars(struct uart_port *the_port)
-{
-       unsigned char ch[IOC4_MAX_CHARS];
-       int read_count, request_count = IOC4_MAX_CHARS;
-       struct uart_icount *icount;
-       struct uart_state *state = the_port->state;
-       unsigned long pflags;
-
-       /* Make sure all the pointers are "good" ones */
-       if (!state)
-               return;
-
-       spin_lock_irqsave(&the_port->lock, pflags);
-
-       request_count = tty_buffer_request_room(&state->port, IOC4_MAX_CHARS);
-
-       if (request_count > 0) {
-               icount = &the_port->icount;
-               read_count = do_read(the_port, ch, request_count);
-               if (read_count > 0) {
-                       tty_insert_flip_string(&state->port, ch, read_count);
-                       icount->rx += read_count;
-               }
-       }
-
-       spin_unlock_irqrestore(&the_port->lock, pflags);
-
-       tty_flip_buffer_push(&state->port);
-}
-
-/**
- * ic4_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic4_type(struct uart_port *the_port)
-{
-       if (the_port->mapbase == PROTO_RS232)
-               return "SGI IOC4 Serial [rs232]";
-       else
-               return "SGI IOC4 Serial [rs422]";
-}
-
-/**
- * ic4_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic4_tx_empty(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       unsigned int ret = 0;
-
-       if (port_is_active(port, the_port)) {
-               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
-                       ret = TIOCSER_TEMT;
-       }
-       return ret;
-}
-
-/**
- * ic4_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic4_stop_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port))
-               set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * null_void_function -
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic4_shutdown - shut down the port - free irq and disable
- * @port: Port to shut down
- *
- */
-static void ic4_shutdown(struct uart_port *the_port)
-{
-       unsigned long port_flags;
-       struct ioc4_port *port;
-       struct uart_state *state;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port)
-               return;
-
-       state = the_port->state;
-       port->ip_port = NULL;
-
-       wake_up_interruptible(&state->port.delta_msr_wait);
-
-       if (state->port.tty)
-               set_bit(TTY_IO_ERROR, &state->port.tty->flags);
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       set_notification(port, N_ALL, 0);
-       port->ip_flags = PORT_INACTIVE;
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
-       unsigned char mcr = 0;
-       struct ioc4_port *port;
-
-       port = get_ioc4_port(the_port, 0);
-       if (!port_is_active(port, the_port))
-               return;
-
-       if (mctrl & TIOCM_RTS)
-               mcr |= UART_MCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               mcr |= UART_MCR_DTR;
-       if (mctrl & TIOCM_OUT1)
-               mcr |= UART_MCR_OUT1;
-       if (mctrl & TIOCM_OUT2)
-               mcr |= UART_MCR_OUT2;
-       if (mctrl & TIOCM_LOOP)
-               mcr |= UART_MCR_LOOP;
-
-       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
-}
-
-/**
- * ic4_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic4_get_mctrl(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-       uint32_t shadow;
-       unsigned int ret = 0;
-
-       if (!port_is_active(port, the_port))
-               return 0;
-
-       shadow = readl(&port->ip_serial_regs->shadow);
-       if (shadow & IOC4_SHADOW_DCD)
-               ret |= TIOCM_CAR;
-       if (shadow & IOC4_SHADOW_DR)
-               ret |= TIOCM_DSR;
-       if (shadow & IOC4_SHADOW_CTS)
-               ret |= TIOCM_CTS;
-       return ret;
-}
-
-/**
- * ic4_start_tx - Start transmitter, flush any output
- * @port: Port to operate on
- *
- */
-static void ic4_start_tx(struct uart_port *the_port)
-{
-       struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
-       if (port_is_active(port, the_port)) {
-               set_notification(port, N_OUTPUT_LOWAT, 1);
-               enable_intrs(port, port->ip_hooks->intr_tx_mt);
-       }
-}
-
-/**
- * ic4_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic4_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic4_startup - Start up the serial port
- * @port: Port to operate on
- *
- */
-static int ic4_startup(struct uart_port *the_port)
-{
-       int retval;
-       struct ioc4_port *port;
-       struct ioc4_control *control;
-       struct uart_state *state;
-       unsigned long port_flags;
-
-       if (!the_port)
-               return -ENODEV;
-       port = get_ioc4_port(the_port, 1);
-       if (!port)
-               return -ENODEV;
-       state = the_port->state;
-
-       control = port->ip_control;
-       if (!control) {
-               port->ip_port = NULL;
-               return -ENODEV;
-       }
-
-       /* Start up the serial port */
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       retval = ic4_startup_local(the_port);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-       return retval;
-}
-
-/**
- * ic4_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic4_set_termios(struct uart_port *the_port,
-               struct ktermios *termios, struct ktermios *old_termios)
-{
-       unsigned long port_flags;
-
-       spin_lock_irqsave(&the_port->lock, port_flags);
-       ioc4_change_speed(the_port, termios, old_termios);
-       spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic4_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static const struct uart_ops ioc4_ops = {
-       .tx_empty       = ic4_tx_empty,
-       .set_mctrl      = ic4_set_mctrl,
-       .get_mctrl      = ic4_get_mctrl,
-       .stop_tx        = ic4_stop_tx,
-       .start_tx       = ic4_start_tx,
-       .stop_rx        = null_void_function,
-       .break_ctl      = ic4_break_ctl,
-       .startup        = ic4_startup,
-       .shutdown       = ic4_shutdown,
-       .set_termios    = ic4_set_termios,
-       .type           = ic4_type,
-       .release_port   = null_void_function,
-       .request_port   = ic4_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc4_uart_rs232 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs232",
-       .dev_name       = DEVICE_NAME_RS232,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS232,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-static struct uart_driver ioc4_uart_rs422 = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial_rs422",
-       .dev_name       = DEVICE_NAME_RS422,
-       .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR_RS422,
-       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
-       int port_num, port_type;
-       struct ioc4_control *control;
-       struct uart_port *the_port;
-       struct ioc4_port *port;
-       struct ioc4_soft *soft;
-
-       /* If serial driver did not attach, don't try to detach */
-       control = idd->idd_serial_data;
-       if (!control)
-               return 0;
-
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               for (port_type = UART_PORT_MIN;
-                                       port_type < UART_PORT_COUNT;
-                                       port_type++) {
-                       the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type];
-                       if (the_port) {
-                               switch (port_type) {
-                               case UART_PORT_RS422:
-                                       uart_remove_one_port(&ioc4_uart_rs422,
-                                                       the_port);
-                                       break;
-                               default:
-                               case UART_PORT_RS232:
-                                       uart_remove_one_port(&ioc4_uart_rs232,
-                                                       the_port);
-                                       break;
-                               }
-                       }
-               }
-               port = control->ic_port[port_num].icp_port;
-               /* we allocate in pairs */
-               if (!(port_num & 1) && port) {
-                       pci_free_consistent(port->ip_pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                       kfree(port);
-               }
-       }
-       soft = control->ic_soft;
-       if (soft) {
-               free_irq(control->ic_irq, soft);
-               if (soft->is_ioc4_serial_addr) {
-                       iounmap(soft->is_ioc4_serial_addr);
-                       release_mem_region((unsigned long)
-                            soft->is_ioc4_serial_addr,
-                               sizeof(struct ioc4_serial));
-               }
-               kfree(soft);
-       }
-       kfree(control);
-       idd->idd_serial_data = NULL;
-
-       return 0;
-}
-
-
-/**
- * ioc4_serial_core_attach_rs232 - register with serial core
- *             This is done during pci probing
- * @pdev: handle for this card
- */
-static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
-{
-       struct ioc4_port *port;
-       struct uart_port *the_port;
-       struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
-       struct ioc4_control *control = idd->idd_serial_data;
-       int port_num;
-       int port_type_idx;
-       struct uart_driver *u_driver;
-
-
-       DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
-                       __func__, pdev, (void *)control));
-
-       if (!control)
-               return -ENODEV;
-
-       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
-                                               : UART_PORT_RS422;
-
-       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
-                                               : &ioc4_uart_rs422;
-
-       /* once around for each port on this card */
-       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
-               the_port = &control->ic_port[port_num].icp_uart_port
-                                                       [port_type_idx];
-               port = control->ic_port[port_num].icp_port;
-               port->ip_all_ports[port_type_idx] = the_port;
-
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
-                               __func__, (void *)the_port,
-                               (void *)port,
-                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
-
-               /* membase, iobase and mapbase just need to be non-0 */
-               the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  port_num;
-               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
-               the_port->mapbase = port_type;
-               the_port->type = PORT_16550A;
-               the_port->fifosize = IOC4_FIFO_CHARS;
-               the_port->ops = &ioc4_ops;
-               the_port->irq = control->ic_irq;
-               the_port->dev = &pdev->dev;
-               spin_lock_init(&the_port->lock);
-               if (uart_add_one_port(u_driver, the_port) < 0) {
-                       printk(KERN_WARNING
-                          "%s: unable to add port %d bus %d\n",
-                              __func__, the_port->line, pdev->bus->number);
-               } else {
-                       DPRINT_CONFIG(
-                           ("IOC4 serial port %d irq = %d, bus %d\n",
-                              the_port->line, the_port->irq, pdev->bus->number));
-               }
-       }
-       return 0;
-}
-
-/**
- * ioc4_serial_attach_one - register attach function
- *             called per card found from IOC4 master module.
- * @idd: Master module data for this IOC4
- */
-static int
-ioc4_serial_attach_one(struct ioc4_driver_data *idd)
-{
-       unsigned long tmp_addr1;
-       struct ioc4_serial __iomem *serial;
-       struct ioc4_soft *soft;
-       struct ioc4_control *control;
-       int ret = 0;
-
-
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
-                                                       idd->idd_pci_id));
-
-       /* PCI-RT does not bring out serial connections.
-        * Do not attach to this particular IOC4.
-        */
-       if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
-               return 0;
-
-       /* request serial registers */
-       tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
-
-       if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
-                                       "sioc4_uart")) {
-               printk(KERN_WARNING
-                       "ioc4 (%p): unable to get request region for "
-                               "uart space\n", (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out1;
-       }
-       serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
-       if (!serial) {
-               printk(KERN_WARNING
-                        "ioc4 (%p) : unable to remap ioc4 serial register\n",
-                               (void *)idd->idd_pdev);
-               ret = -ENODEV;
-               goto out2;
-       }
-       DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
-                               __func__, (void *)idd->idd_misc_regs,
-                               (void *)serial));
-
-       /* Get memory for the new card */
-       control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
-
-       if (!control) {
-               printk(KERN_WARNING "ioc4_attach_one"
-                      ": unable to get memory for the IOC4\n");
-               ret = -ENOMEM;
-               goto out2;
-       }
-       idd->idd_serial_data = control;
-
-       /* Allocate the soft structure */
-       soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
-       if (!soft) {
-               printk(KERN_WARNING
-                      "ioc4 (%p): unable to get memory for the soft struct\n",
-                      (void *)idd->idd_pdev);
-               ret = -ENOMEM;
-               goto out3;
-       }
-
-       spin_lock_init(&soft->is_ir_lock);
-       soft->is_ioc4_misc_addr = idd->idd_misc_regs;
-       soft->is_ioc4_serial_addr = serial;
-
-       /* Init the IOC4 */
-       writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
-              &idd->idd_misc_regs->sio_cr.raw);
-
-       /* Enable serial port mode select generic PIO pins as outputs */
-       writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
-               | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
-               &idd->idd_misc_regs->gpcr_s.raw);
-
-       /* Clear and disable all serial interrupts */
-       write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
-       writel(~0, &idd->idd_misc_regs->sio_ir.raw);
-       write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
-                  IOC4_OTHER_INTR_TYPE);
-       writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
-       control->ic_soft = soft;
-
-       /* Hook up interrupt handler */
-       if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
-                               "sgi-ioc4serial", soft)) {
-               control->ic_irq = idd->idd_pdev->irq;
-       } else {
-               printk(KERN_WARNING
-                   "%s : request_irq fails for IRQ 0x%x\n ",
-                       __func__, idd->idd_pdev->irq);
-       }
-       ret = ioc4_attach_local(idd);
-       if (ret)
-               goto out4;
-
-       /* register port with the serial core - 1 rs232, 1 rs422 */
-
-       ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232);
-       if (ret)
-               goto out4;
-
-       ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422);
-       if (ret)
-               goto out5;
-
-       Num_of_ioc4_cards++;
-
-       return ret;
-
-       /* error exits that give back resources */
-out5:
-       ioc4_serial_remove_one(idd);
-       return ret;
-out4:
-       kfree(soft);
-out3:
-       kfree(control);
-out2:
-       if (serial)
-               iounmap(serial);
-       release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
-out1:
-
-       return ret;
-}
-
-
-static struct ioc4_submodule ioc4_serial_submodule = {
-       .is_name = "IOC4_serial",
-       .is_owner = THIS_MODULE,
-       .is_probe = ioc4_serial_attach_one,
-       .is_remove = ioc4_serial_remove_one,
-};
-
-/**
- * ioc4_serial_init - module init
- */
-static int __init ioc4_serial_init(void)
-{
-       int ret;
-
-       /* register with serial core */
-       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs232 IOC4 serial driver\n",
-                       __func__);
-               goto out;
-       }
-       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
-               printk(KERN_WARNING
-                       "%s: Couldn't register rs422 IOC4 serial driver\n",
-                       __func__);
-               goto out_uart_rs232;
-       }
-
-       /* register with IOC4 main module */
-       ret = ioc4_register_submodule(&ioc4_serial_submodule);
-       if (ret)
-               goto out_uart_rs422;
-       return 0;
-
-out_uart_rs422:
-       uart_unregister_driver(&ioc4_uart_rs422);
-out_uart_rs232:
-       uart_unregister_driver(&ioc4_uart_rs232);
-out:
-       return ret;
-}
-
-static void __exit ioc4_serial_exit(void)
-{
-       ioc4_unregister_submodule(&ioc4_serial_submodule);
-       uart_unregister_driver(&ioc4_uart_rs232);
-       uart_unregister_driver(&ioc4_uart_rs422);
-}
-
-late_initcall(ioc4_serial_init); /* Call only after tty init is done */
-module_exit(ioc4_serial_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
deleted file mode 100644 (file)
index 2834933..0000000
+++ /dev/null
@@ -1,1036 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * C-Brick Serial Port (and console) driver for SGI Altix machines.
- *
- * This driver is NOT suitable for talking to the l1-controller for
- * anything other than 'console activities' --- please use the l1
- * driver for that.
- *
- *
- * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h> /* for mdelay */
-#include <linux/miscdevice.h>
-#include <linux/serial_core.h>
-
-#include <asm/io.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/sn_sal.h>
-
-/* number of characters we can transmit to the SAL console at a time */
-#define SN_SAL_MAX_CHARS 120
-
-/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
- * avoid losing chars, (always has to be a power of 2) */
-#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
-
-#define SN_SAL_UART_FIFO_DEPTH 16
-#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
-
-/* sn_transmit_chars() calling args */
-#define TRANSMIT_BUFFERED      0
-#define TRANSMIT_RAW           1
-
-/* To use dynamic numbers only and not use the assigned major and minor,
- * define the following.. */
-                                 /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
-#define USE_DYNAMIC_MINOR 0    /* Don't rely on misc_register dynamic minor */
-
-/* Device name we're using */
-#define DEVICE_NAME "ttySG"
-#define DEVICE_NAME_DYNAMIC "ttySG0"   /* need full name for misc_register */
-/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 40
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static char sysrq_serial_str[] = "\eSYS";
-static char *sysrq_serial_ptr = sysrq_serial_str;
-static unsigned long sysrq_requested;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-/*
- * Port definition - this kinda drives it all
- */
-struct sn_cons_port {
-       struct timer_list sc_timer;
-       struct uart_port sc_port;
-       struct sn_sal_ops {
-               int (*sal_puts_raw) (const char *s, int len);
-               int (*sal_puts) (const char *s, int len);
-               int (*sal_getc) (void);
-               int (*sal_input_pending) (void);
-               void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
-       } *sc_ops;
-       unsigned long sc_interrupt_timeout;
-       int sc_is_asynch;
-};
-
-static struct sn_cons_port sal_console_port;
-static int sn_process_input;
-
-/* Only used if USE_DYNAMIC_MINOR is set to 1 */
-static struct miscdevice misc; /* used with misc_register for dynamic */
-
-extern void early_sn_setup(void);
-
-#undef DEBUG
-#ifdef DEBUG
-static int sn_debug_printf(const char *fmt, ...);
-#define DPRINTF(x...) sn_debug_printf(x)
-#else
-#define DPRINTF(x...) do { } while (0)
-#endif
-
-/* Prototypes */
-static int snt_hw_puts_raw(const char *, int);
-static int snt_hw_puts_buffered(const char *, int);
-static int snt_poll_getc(void);
-static int snt_poll_input_pending(void);
-static int snt_intr_getc(void);
-static int snt_intr_input_pending(void);
-static void sn_transmit_chars(struct sn_cons_port *, int);
-
-/* A table for polling:
- */
-static struct sn_sal_ops poll_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_raw,
-       .sal_getc = snt_poll_getc,
-       .sal_input_pending = snt_poll_input_pending
-};
-
-/* A table for interrupts enabled */
-static struct sn_sal_ops intr_ops = {
-       .sal_puts_raw = snt_hw_puts_raw,
-       .sal_puts = snt_hw_puts_buffered,
-       .sal_getc = snt_intr_getc,
-       .sal_input_pending = snt_intr_input_pending,
-       .sal_wakeup_transmit = sn_transmit_chars
-};
-
-/* the console does output in two distinctly different ways:
- * synchronous (raw) and asynchronous (buffered).  initially, early_printk
- * does synchronous output.  any data written goes directly to the SAL
- * to be output (incidentally, it is internally buffered by the SAL)
- * after interrupts and timers are initialized and available for use,
- * the console init code switches to asynchronous output.  this is
- * also the earliest opportunity to begin polling for console input.
- * after console initialization, console output and tty (serial port)
- * output is buffered and sent to the SAL asynchronously (either by
- * timer callback or by UART interrupt) */
-
-/* routines for running the console in polling mode */
-
-/**
- * snt_poll_getc - Get a character from the console in polling mode
- *
- */
-static int snt_poll_getc(void)
-{
-       int ch;
-
-       ia64_sn_console_getc(&ch);
-       return ch;
-}
-
-/**
- * snt_poll_input_pending - Check if any input is waiting - polling mode.
- *
- */
-static int snt_poll_input_pending(void)
-{
-       int status, input;
-
-       status = ia64_sn_console_check(&input);
-       return !status && input;
-}
-
-/* routines for an interrupt driven console (normal) */
-
-/**
- * snt_intr_getc - Get a character from the console, interrupt mode
- *
- */
-static int snt_intr_getc(void)
-{
-       return ia64_sn_console_readc();
-}
-
-/**
- * snt_intr_input_pending - Check if input is pending, interrupt mode
- *
- */
-static int snt_intr_input_pending(void)
-{
-       return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
-}
-
-/* these functions are polled and interrupt */
-
-/**
- * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_raw(const char *s, int len)
-{
-       /* this will call the PROM and not return until this is done */
-       return ia64_sn_console_putb(s, len);
-}
-
-/**
- * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_buffered(const char *s, int len)
-{
-       /* queue data to the PROM */
-       return ia64_sn_console_xmit_chars((char *)s, len);
-}
-
-/* uart interface structs
- * These functions are associated with the uart_port that the serial core
- * infrastructure calls.
- *
- * Note: Due to how the console works, many routines are no-ops.
- */
-
-/**
- * snp_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *snp_type(struct uart_port *port)
-{
-       return ("SGI SN L1");
-}
-
-/**
- * snp_tx_empty - Is the transmitter empty?  We pretend we're always empty
- * @port: Port to operate on (we ignore since we only have one port)
- *
- */
-static unsigned int snp_tx_empty(struct uart_port *port)
-{
-       return 1;
-}
-
-/**
- * snp_stop_tx - stop the transmitter - no-op for us
- * @port: Port to operat eon - we ignore - no-op function
- *
- */
-static void snp_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * snp_release_port - Free i/o and resources for port - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_release_port(struct uart_port *port)
-{
-}
-
-/**
- * snp_shutdown - shut down the port - free irq and disable - no-op for us
- * @port: Port to shut down - we ignore
- *
- */
-static void snp_shutdown(struct uart_port *port)
-{
-}
-
-/**
- * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
- * @port: Port to operate on - we ignore
- * @mctrl: Lines to set/unset - we ignore
- *
- */
-static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * snp_get_mctrl - get contorl line info, we just return a static value
- * @port: port to operate on - we only have one port so we ignore this
- *
- */
-static unsigned int snp_get_mctrl(struct uart_port *port)
-{
-       return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * snp_stop_rx - Stop the receiver - we ignor ethis
- * @port: Port to operate on - we ignore
- *
- */
-static void snp_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * snp_start_tx - Start transmitter
- * @port: Port to operate on
- *
- */
-static void snp_start_tx(struct uart_port *port)
-{
-       if (sal_console_port.sc_ops->sal_wakeup_transmit)
-               sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
-                                                            TRANSMIT_BUFFERED);
-
-}
-
-/**
- * snp_break_ctl - handle breaks - ignored by us
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void snp_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * snp_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int snp_startup(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_set_termios - set termios stuff - we ignore these
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-snp_set_termios(struct uart_port *port, struct ktermios *termios,
-               struct ktermios *old)
-{
-}
-
-/**
- * snp_request_port - allocate resources for port - ignored by us
- * @port: port to operate on
- *
- */
-static int snp_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-/**
- * snp_config_port - allocate resources, set up - we ignore,  we're always on
- * @port: Port to operate on
- * @flags: flags used for port setup
- *
- */
-static void snp_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static const struct uart_ops sn_console_ops = {
-       .tx_empty = snp_tx_empty,
-       .set_mctrl = snp_set_mctrl,
-       .get_mctrl = snp_get_mctrl,
-       .stop_tx = snp_stop_tx,
-       .start_tx = snp_start_tx,
-       .stop_rx = snp_stop_rx,
-       .break_ctl = snp_break_ctl,
-       .startup = snp_startup,
-       .shutdown = snp_shutdown,
-       .set_termios = snp_set_termios,
-       .pm = NULL,
-       .type = snp_type,
-       .release_port = snp_release_port,
-       .request_port = snp_request_port,
-       .config_port = snp_config_port,
-       .verify_port = NULL,
-};
-
-/* End of uart struct functions and defines */
-
-#ifdef DEBUG
-
-/**
- * sn_debug_printf - close to hardware debugging printf
- * @fmt: printf format
- *
- * This is as "close to the metal" as we can get, used when the driver
- * itself may be broken.
- *
- */
-static int sn_debug_printf(const char *fmt, ...)
-{
-       static char printk_buf[1024];
-       int printed_len;
-       va_list args;
-
-       va_start(args, fmt);
-       printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-
-       if (!sal_console_port.sc_ops) {
-               sal_console_port.sc_ops = &poll_ops;
-               early_sn_setup();
-       }
-       sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
-
-       va_end(args);
-       return printed_len;
-}
-#endif                         /* DEBUG */
-
-/*
- * Interrupt handling routines.
- */
-
-/**
- * sn_receive_chars - Grab characters, pass them to tty layer
- * @port: Port to operate on
- * @flags: irq flags
- *
- * Note: If we're not registered with the serial core infrastructure yet,
- * we don't try to send characters to it...
- *
- */
-static void
-sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
-{
-       struct tty_port *tport = NULL;
-       int ch;
-
-       if (!port) {
-               printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
-               return;
-       }
-
-       if (!port->sc_ops) {
-               printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receive\n");
-               return;
-       }
-
-       if (port->sc_port.state) {
-               /* The serial_core stuffs are initialized, use them */
-               tport = &port->sc_port.state->port;
-       }
-
-       while (port->sc_ops->sal_input_pending()) {
-               ch = port->sc_ops->sal_getc();
-               if (ch < 0) {
-                       printk(KERN_ERR "sn_console: An error occurred while "
-                              "obtaining data from the console (0x%0x)\n", ch);
-                       break;
-               }
-#ifdef CONFIG_MAGIC_SYSRQ
-                if (sysrq_requested) {
-                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
-
-                        sysrq_requested = 0;
-                        if (ch && time_before(jiffies, sysrq_timeout)) {
-                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                                handle_sysrq(ch);
-                                spin_lock_irqsave(&port->sc_port.lock, flags);
-                                /* ignore actual sysrq command char */
-                                continue;
-                        }
-                }
-                if (ch == *sysrq_serial_ptr) {
-                        if (!(*++sysrq_serial_ptr)) {
-                                sysrq_requested = jiffies;
-                                sysrq_serial_ptr = sysrq_serial_str;
-                        }
-                       /*
-                        * ignore the whole sysrq string except for the
-                        * leading escape
-                        */
-                       if (ch != '\e')
-                               continue;
-                }
-                else
-                       sysrq_serial_ptr = sysrq_serial_str;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-               /* record the character to pass up to the tty layer */
-               if (tport) {
-                       if (tty_insert_flip_char(tport, ch, TTY_NORMAL) == 0)
-                               break;
-               }
-               port->sc_port.icount.rx++;
-       }
-
-       if (tport)
-               tty_flip_buffer_push(tport);
-}
-
-/**
- * sn_transmit_chars - grab characters from serial core, send off
- * @port: Port to operate on
- * @raw: Transmit raw or buffered
- *
- * Note: If we're early, before we're registered with serial core, the
- * writes are going through sn_sal_console_write because that's how
- * register_console has been set up.  We currently could have asynch
- * polls calling this function due to sn_sal_switch_to_asynch but we can
- * ignore them until we register with the serial core stuffs.
- *
- */
-static void sn_transmit_chars(struct sn_cons_port *port, int raw)
-{
-       int xmit_count, tail, head, loops, ii;
-       int result;
-       char *start;
-       struct circ_buf *xmit;
-
-       if (!port)
-               return;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       if (port->sc_port.state) {
-               /* We're initialized, using serial core infrastructure */
-               xmit = &port->sc_port.state->xmit;
-       } else {
-               /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
-                * initialized yet.  Just return.  Writes are going through
-                * sn_sal_console_write (due to register_console) at this time.
-                */
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
-               /* Nothing to do. */
-               ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
-               return;
-       }
-
-       head = xmit->head;
-       tail = xmit->tail;
-       start = &xmit->buf[tail];
-
-       /* twice around gets the tail to the end of the buffer and
-        * then to the head, if needed */
-       loops = (head < tail) ? 2 : 1;
-
-       for (ii = 0; ii < loops; ii++) {
-               xmit_count = (head < tail) ?
-                   (UART_XMIT_SIZE - tail) : (head - tail);
-
-               if (xmit_count > 0) {
-                       if (raw == TRANSMIT_RAW)
-                               result =
-                                   port->sc_ops->sal_puts_raw(start,
-                                                              xmit_count);
-                       else
-                               result =
-                                   port->sc_ops->sal_puts(start, xmit_count);
-#ifdef DEBUG
-                       if (!result)
-                               DPRINTF("`");
-#endif
-                       if (result > 0) {
-                               xmit_count -= result;
-                               port->sc_port.icount.tx += result;
-                               tail += result;
-                               tail &= UART_XMIT_SIZE - 1;
-                               xmit->tail = tail;
-                               start = &xmit->buf[tail];
-                       }
-               }
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&port->sc_port);
-
-       if (uart_circ_empty(xmit))
-               snp_stop_tx(&port->sc_port);    /* no-op for us */
-}
-
-/**
- * sn_sal_interrupt - Handle console interrupts
- * @irq: irq #, useful for debug statements
- * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
- *
- */
-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
-{
-       struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
-       unsigned long flags;
-       int status = ia64_sn_console_intr_status();
-
-       if (!port)
-               return IRQ_NONE;
-
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-       if (status & SAL_CONSOLE_INTR_RECV) {
-               sn_receive_chars(port, flags);
-       }
-       if (status & SAL_CONSOLE_INTR_XMIT) {
-               sn_transmit_chars(port, TRANSMIT_BUFFERED);
-       }
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-       return IRQ_HANDLED;
-}
-
-/**
- * sn_sal_timer_poll - this function handles polled console mode
- * @data: A pointer to our sn_cons_port (which contains the uart port)
- *
- * data is the pointer that init_timer will store for us.  This function is
- * associated with init_timer to see if there is any console traffic.
- * Obviously not used in interrupt mode
- *
- */
-static void sn_sal_timer_poll(struct timer_list *t)
-{
-       struct sn_cons_port *port = from_timer(port, t, sc_timer);
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       if (!port->sc_port.irq) {
-               spin_lock_irqsave(&port->sc_port.lock, flags);
-               if (sn_process_input)
-                       sn_receive_chars(port, flags);
-               sn_transmit_chars(port, TRANSMIT_RAW);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               mod_timer(&port->sc_timer,
-                         jiffies + port->sc_interrupt_timeout);
-       }
-}
-
-/*
- * Boot-time initialization code
- */
-
-/**
- * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * So this is used by sn_sal_serial_console_init (early on, before we're
- * registered with serial core).  It's also used by sn_sal_init
- * right after we've registered with serial core.  The later only happens
- * if we didn't already come through here via sn_sal_serial_console_init.
- *
- */
-static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (!port)
-               return;
-
-       DPRINTF("sn_console: about to switch to asynchronous console\n");
-
-       /* without early_printk, we may be invoked late enough to race
-        * with other cpus doing console IO at this point, however
-        * console interrupts will never be enabled */
-       spin_lock_irqsave(&port->sc_port.lock, flags);
-
-       /* early_printk invocation may have done this for us */
-       if (!port->sc_ops)
-               port->sc_ops = &poll_ops;
-
-       /* we can't turn on the console interrupt (as request_irq
-        * calls kmalloc, which isn't set up yet), so we rely on a
-        * timer to poll for input and push data from the console
-        * buffer.
-        */
-       timer_setup(&port->sc_timer, sn_sal_timer_poll, 0);
-
-       if (IS_RUNNING_ON_SIMULATOR())
-               port->sc_interrupt_timeout = 6;
-       else {
-               /* 960cps / 16 char FIFO = 60HZ
-                * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
-               port->sc_interrupt_timeout =
-                   HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
-       }
-       mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
-
-       port->sc_is_asynch = 1;
-       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-}
-
-/**
- * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * In sn_sal_init, after we're registered with serial core and
- * the port is added, this function is called to switch us to interrupt
- * mode.  We were previously in asynch/polling mode (using init_timer).
- *
- * We attempt to switch to interrupt mode here by calling
- * request_irq.  If that works out, we enable receive interrupts.
- */
-static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
-{
-       unsigned long flags;
-
-       if (port) {
-               DPRINTF("sn_console: switching to interrupt driven console\n");
-
-               if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
-                               IRQF_SHARED,
-                               "SAL console driver", port) >= 0) {
-                       spin_lock_irqsave(&port->sc_port.lock, flags);
-                       port->sc_port.irq = SGI_UART_VECTOR;
-                       port->sc_ops = &intr_ops;
-                       irq_set_handler(port->sc_port.irq, handle_level_irq);
-
-                       /* turn on receive interrupts */
-                       ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-               }
-               else {
-                       printk(KERN_INFO
-                           "sn_console: console proceeding in polled mode\n");
-               }
-       }
-}
-
-/*
- * Kernel console definitions
- */
-
-static void sn_sal_console_write(struct console *, const char *, unsigned);
-static int sn_sal_console_setup(struct console *, char *);
-static struct uart_driver sal_console_uart;
-extern struct tty_driver *uart_console_device(struct console *, int *);
-
-static struct console sal_console = {
-       .name = DEVICE_NAME,
-       .write = sn_sal_console_write,
-       .device = uart_console_device,
-       .setup = sn_sal_console_setup,
-       .index = -1,            /* unspecified */
-       .data = &sal_console_uart,
-};
-
-#define SAL_CONSOLE    &sal_console
-
-static struct uart_driver sal_console_uart = {
-       .owner = THIS_MODULE,
-       .driver_name = "sn_console",
-       .dev_name = DEVICE_NAME,
-       .major = 0,             /* major/minor set at registration time per USE_DYNAMIC_MINOR */
-       .minor = 0,
-       .nr = 1,                /* one port */
-       .cons = SAL_CONSOLE,
-};
-
-/**
- * sn_sal_init - When the kernel loads us, get us rolling w/ serial core
- *
- * Before this is called, we've been printing kernel messages in a special
- * early mode not making use of the serial core infrastructure.  When our
- * driver is loaded for real, we register the driver and port with serial
- * core and try to enable interrupt driven mode.
- *
- */
-static int __init sn_sal_init(void)
-{
-       int retval;
-
-       if (!ia64_platform_is("sn2"))
-               return 0;
-
-       printk(KERN_INFO "sn_console: Console driver init\n");
-
-       if (USE_DYNAMIC_MINOR == 1) {
-               misc.minor = MISC_DYNAMIC_MINOR;
-               misc.name = DEVICE_NAME_DYNAMIC;
-               retval = misc_register(&misc);
-               if (retval != 0) {
-                       printk(KERN_WARNING "Failed to register console "
-                              "device using misc_register.\n");
-                       return -ENODEV;
-               }
-               sal_console_uart.major = MISC_MAJOR;
-               sal_console_uart.minor = misc.minor;
-       } else {
-               sal_console_uart.major = DEVICE_MAJOR;
-               sal_console_uart.minor = DEVICE_MINOR;
-       }
-
-       /* We register the driver and the port before switching to interrupts
-        * or async above so the proper uart structures are populated */
-
-       if (uart_register_driver(&sal_console_uart) < 0) {
-               printk
-                   ("ERROR sn_sal_init failed uart_register_driver, line %d\n",
-                    __LINE__);
-               return -ENODEV;
-       }
-
-       spin_lock_init(&sal_console_port.sc_port.lock);
-
-       /* Setup the port struct with the minimum needed */
-       sal_console_port.sc_port.membase = (char *)1;   /* just needs to be non-zero */
-       sal_console_port.sc_port.type = PORT_16550A;
-       sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
-       sal_console_port.sc_port.ops = &sn_console_ops;
-       sal_console_port.sc_port.line = 0;
-
-       if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
-               /* error - not sure what I'd do - so I'll do nothing */
-               printk(KERN_ERR "%s: unable to add port\n", __func__);
-       }
-
-       /* when this driver is compiled in, the console initialization
-        * will have already switched us into asynchronous operation
-        * before we get here through the initcalls */
-       if (!sal_console_port.sc_is_asynch) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-       }
-
-       /* at this point (device_init) we can try to turn on interrupts */
-       if (!IS_RUNNING_ON_SIMULATOR()) {
-               sn_sal_switch_to_interrupts(&sal_console_port);
-       }
-       sn_process_input = 1;
-       return 0;
-}
-device_initcall(sn_sal_init);
-
-/**
- * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
- * @puts_raw : puts function to do the writing
- * @s: input string
- * @count: length
- *
- * We need a \r ahead of every \n for direct writes through
- * ia64_sn_console_putb (what sal_puts_raw below actually does).
- *
- */
-
-static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
-                          const char *s, int count)
-{
-       const char *s1;
-
-       /* Output '\r' before each '\n' */
-       while ((s1 = memchr(s, '\n', count)) != NULL) {
-               puts_raw(s, s1 - s);
-               puts_raw("\r\n", 2);
-               count -= s1 + 1 - s;
-               s = s1 + 1;
-       }
-       puts_raw(s, count);
-}
-
-/**
- * sn_sal_console_write - Print statements before serial core available
- * @console: Console to operate on - we ignore since we have just one
- * @s: String to send
- * @count: length
- *
- * This is referenced in the console struct.  It is used for early
- * console printing before we register with serial core and for things
- * such as kdb.  The console_lock must be held when we get here.
- *
- * This function has some code for trying to print output even if the lock
- * is held.  We try to cover the case where a lock holder could have died.
- * We don't use this special case code if we're not registered with serial
- * core yet.  After we're registered with serial core, the only time this
- * function would be used is for high level kernel output like magic sys req,
- * kdb, and printk's.
- */
-static void
-sn_sal_console_write(struct console *co, const char *s, unsigned count)
-{
-       unsigned long flags = 0;
-       struct sn_cons_port *port = &sal_console_port;
-       static int stole_lock = 0;
-
-       BUG_ON(!port->sc_is_asynch);
-
-       /* We can't look at the xmit buffer if we're not registered with serial core
-        *  yet.  So only do the fancy recovery after registering
-        */
-       if (!port->sc_port.state) {
-               /* Not yet registered with serial core - simple case */
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-               return;
-       }
-
-       /* somebody really wants this output, might be an
-        * oops, kdb, panic, etc.  make sure they get it. */
-       if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
-               int lhead = port->sc_port.state->xmit.head;
-               int ltail = port->sc_port.state->xmit.tail;
-               int counter, got_lock = 0;
-
-               /*
-                * We attempt to determine if someone has died with the
-                * lock. We wait ~20 secs after the head and tail ptrs
-                * stop moving and assume the lock holder is not functional
-                * and plow ahead. If the lock is freed within the time out
-                * period we re-get the lock and go ahead normally. We also
-                * remember if we have plowed ahead so that we don't have
-                * to wait out the time out period again - the asumption
-                * is that we will time out again.
-                */
-
-               for (counter = 0; counter < 150; mdelay(125), counter++) {
-                       if (stole_lock)
-                               break;
-
-                       if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
-                               got_lock = 1;
-                               break;
-                       } else {
-                               /* still locked */
-                               if ((lhead != port->sc_port.state->xmit.head)
-                                   || (ltail !=
-                                       port->sc_port.state->xmit.tail)) {
-                                       lhead =
-                                               port->sc_port.state->xmit.head;
-                                       ltail =
-                                               port->sc_port.state->xmit.tail;
-                                       counter = 0;
-                               }
-                       }
-               }
-               /* flush anything in the serial core xmit buffer, raw */
-               sn_transmit_chars(port, 1);
-               if (got_lock) {
-                       spin_unlock_irqrestore(&port->sc_port.lock, flags);
-                       stole_lock = 0;
-               } else {
-                       /* fell thru */
-                       stole_lock = 1;
-               }
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       } else {
-               stole_lock = 0;
-               sn_transmit_chars(port, 1);
-               spin_unlock_irqrestore(&port->sc_port.lock, flags);
-
-               puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
-       }
-}
-
-
-/**
- * sn_sal_console_setup - Set up console for early printing
- * @co: Console to work with
- * @options: Options to set
- *
- * Altix console doesn't do anything with baud rates, etc, anyway.
- *
- * This isn't required since not providing the setup function in the
- * console struct is ok.  However, other patches like KDB plop something
- * here so providing it is easier.
- *
- */
-static int sn_sal_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-/**
- * sn_sal_console_write_early - simple early output routine
- * @co - console struct
- * @s - string to print
- * @count - count
- *
- * Simple function to provide early output, before even
- * sn_sal_serial_console_init is called.  Referenced in the
- * console struct registerd in sn_serial_console_early_setup.
- *
- */
-static void __init
-sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
-{
-       puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
-}
-
-/* Used for very early console printing - again, before
- * sn_sal_serial_console_init is run */
-static struct console sal_console_early __initdata = {
-       .name = "sn_sal",
-       .write = sn_sal_console_write_early,
-       .flags = CON_PRINTBUFFER,
-       .index = -1,
-};
-
-/**
- * sn_serial_console_early_setup - Sets up early console output support
- *
- * Register a console early on...  This is for output before even
- * sn_sal_serial_cosnole_init is called.  This function is called from
- * setup.c.  This allows us to do really early polled writes. When
- * sn_sal_serial_console_init is called, this console is unregistered
- * and a new one registered.
- */
-int __init sn_serial_console_early_setup(void)
-{
-       if (!ia64_platform_is("sn2"))
-               return -1;
-
-       sal_console_port.sc_ops = &poll_ops;
-       spin_lock_init(&sal_console_port.sc_port.lock);
-       early_sn_setup();       /* Find SAL entry points */
-       register_console(&sal_console_early);
-
-       return 0;
-}
-
-/**
- * sn_sal_serial_console_init - Early console output - set up for register
- *
- * This function is called when regular console init happens.  Because we
- * support even earlier console output with sn_serial_console_early_setup
- * (called from setup.c directly), this function unregisters the really
- * early console.
- *
- * Note: Even if setup.c doesn't register sal_console_early, unregistering
- * it here doesn't hurt anything.
- *
- */
-static int __init sn_sal_serial_console_init(void)
-{
-       if (ia64_platform_is("sn2")) {
-               sn_sal_switch_to_asynch(&sal_console_port);
-               DPRINTF("sn_sal_serial_console_init : register console\n");
-               register_console(&sal_console);
-               unregister_console(&sal_console_early);
-       }
-       return 0;
-}
-
-console_initcall(sn_sal_serial_console_init);
index b5abfe8..df8812c 100644 (file)
@@ -454,9 +454,11 @@ err_clk:
        imx_disable_unprepare_clks(dev);
 disable_hsic_regulator:
        if (data->hsic_pad_regulator)
-               ret = regulator_disable(data->hsic_pad_regulator);
+               /* don't overwrite original ret (cf. EPROBE_DEFER) */
+               regulator_disable(data->hsic_pad_regulator);
        if (pdata.flags & CI_HDRC_PMQOS)
                pm_qos_remove_request(&data->pm_qos_req);
+       data->ci_pdev = NULL;
        return ret;
 }
 
@@ -469,14 +471,17 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
                pm_runtime_disable(&pdev->dev);
                pm_runtime_put_noidle(&pdev->dev);
        }
-       ci_hdrc_remove_device(data->ci_pdev);
+       if (data->ci_pdev)
+               ci_hdrc_remove_device(data->ci_pdev);
        if (data->override_phy_control)
                usb_phy_shutdown(data->phy);
-       imx_disable_unprepare_clks(&pdev->dev);
-       if (data->plat_data->flags & CI_HDRC_PMQOS)
-               pm_qos_remove_request(&data->pm_qos_req);
-       if (data->hsic_pad_regulator)
-               regulator_disable(data->hsic_pad_regulator);
+       if (data->ci_pdev) {
+               imx_disable_unprepare_clks(&pdev->dev);
+               if (data->plat_data->flags & CI_HDRC_PMQOS)
+                       pm_qos_remove_request(&data->pm_qos_req);
+               if (data->hsic_pad_regulator)
+                       regulator_disable(data->hsic_pad_regulator);
+       }
 
        return 0;
 }
index 6a5ee8e..67ad40b 100644 (file)
@@ -709,12 +709,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
        struct ci_hdrc    *ci = container_of(gadget, struct ci_hdrc, gadget);
        unsigned long flags;
 
-       spin_lock_irqsave(&ci->lock, flags);
-       ci->gadget.speed = USB_SPEED_UNKNOWN;
-       ci->remote_wakeup = 0;
-       ci->suspended = 0;
-       spin_unlock_irqrestore(&ci->lock, flags);
-
        /* flush all endpoints */
        gadget_for_each_ep(ep, gadget) {
                usb_ep_fifo_flush(ep);
@@ -732,6 +726,12 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
                ci->status = NULL;
        }
 
+       spin_lock_irqsave(&ci->lock, flags);
+       ci->gadget.speed = USB_SPEED_UNKNOWN;
+       ci->remote_wakeup = 0;
+       ci->suspended = 0;
+       spin_unlock_irqrestore(&ci->lock, flags);
+
        return 0;
 }
 
@@ -1303,6 +1303,10 @@ static int ep_disable(struct usb_ep *ep)
                return -EBUSY;
 
        spin_lock_irqsave(hwep->lock, flags);
+       if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+               spin_unlock_irqrestore(hwep->lock, flags);
+               return 0;
+       }
 
        /* only internal SW should disable ctrl endpts */
 
@@ -1392,6 +1396,10 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
                return -EINVAL;
 
        spin_lock_irqsave(hwep->lock, flags);
+       if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+               spin_unlock_irqrestore(hwep->lock, flags);
+               return 0;
+       }
        retval = _ep_queue(ep, req, gfp_flags);
        spin_unlock_irqrestore(hwep->lock, flags);
        return retval;
@@ -1415,8 +1423,8 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
                return -EINVAL;
 
        spin_lock_irqsave(hwep->lock, flags);
-
-       hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
+       if (hwep->ci->gadget.speed != USB_SPEED_UNKNOWN)
+               hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
 
        list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
                dma_pool_free(hwep->td_pool, node->ptr, node->dma);
@@ -1487,6 +1495,10 @@ static void ep_fifo_flush(struct usb_ep *ep)
        }
 
        spin_lock_irqsave(hwep->lock, flags);
+       if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+               spin_unlock_irqrestore(hwep->lock, flags);
+               return;
+       }
 
        hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
 
@@ -1559,6 +1571,10 @@ static int ci_udc_wakeup(struct usb_gadget *_gadget)
        int ret = 0;
 
        spin_lock_irqsave(&ci->lock, flags);
+       if (ci->gadget.speed == USB_SPEED_UNKNOWN) {
+               spin_unlock_irqrestore(&ci->lock, flags);
+               return 0;
+       }
        if (!ci->remote_wakeup) {
                ret = -EOPNOTSUPP;
                goto out;
index 183b417..62f4fb9 100644 (file)
@@ -1301,10 +1301,6 @@ made_compressed_probe:
        tty_port_init(&acm->port);
        acm->port.ops = &acm_port_ops;
 
-       minor = acm_alloc_minor(acm);
-       if (minor < 0)
-               goto alloc_fail1;
-
        ctrlsize = usb_endpoint_maxp(epctrl);
        readsize = usb_endpoint_maxp(epread) *
                                (quirks == SINGLE_RX_URB ? 1 : 2);
@@ -1312,6 +1308,13 @@ made_compressed_probe:
        acm->writesize = usb_endpoint_maxp(epwrite) * 20;
        acm->control = control_interface;
        acm->data = data_interface;
+
+       usb_get_intf(acm->control); /* undone in destruct() */
+
+       minor = acm_alloc_minor(acm);
+       if (minor < 0)
+               goto alloc_fail1;
+
        acm->minor = minor;
        acm->dev = usb_dev;
        if (h.usb_cdc_acm_descriptor)
@@ -1458,7 +1461,6 @@ skip_countries:
        usb_driver_claim_interface(&acm_driver, data_interface, acm);
        usb_set_intfdata(data_interface, acm);
 
-       usb_get_intf(control_interface);
        tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
                        &control_interface->dev);
        if (IS_ERR(tty_dev)) {
index a7824a5..70afb2c 100644 (file)
@@ -587,10 +587,20 @@ static int wdm_flush(struct file *file, fl_owner_t id)
 {
        struct wdm_device *desc = file->private_data;
 
-       wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
+       wait_event(desc->wait,
+                       /*
+                        * needs both flags. We cannot do with one
+                        * because resetting it would cause a race
+                        * with write() yet we need to signal
+                        * a disconnect
+                        */
+                       !test_bit(WDM_IN_USE, &desc->flags) ||
+                       test_bit(WDM_DISCONNECTING, &desc->flags));
 
        /* cannot dereference desc->intf if WDM_DISCONNECTING */
-       if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
+       if (test_bit(WDM_DISCONNECTING, &desc->flags))
+               return -ENODEV;
+       if (desc->werr < 0)
                dev_err(&desc->intf->dev, "Error in flush path: %d\n",
                        desc->werr);
 
@@ -974,8 +984,6 @@ static void wdm_disconnect(struct usb_interface *intf)
        spin_lock_irqsave(&desc->iuspin, flags);
        set_bit(WDM_DISCONNECTING, &desc->flags);
        set_bit(WDM_READ, &desc->flags);
-       /* to terminate pending flushes */
-       clear_bit(WDM_IN_USE, &desc->flags);
        spin_unlock_irqrestore(&desc->iuspin, flags);
        wake_up_all(&desc->wait);
        mutex_lock(&desc->rlock);
index 4942122..36858dd 100644 (file)
@@ -2362,8 +2362,11 @@ static int usbtmc_probe(struct usb_interface *intf,
                goto err_put;
        }
 
+       retcode = -EINVAL;
        data->bulk_in = bulk_in->bEndpointAddress;
        data->wMaxPacketSize = usb_endpoint_maxp(bulk_in);
+       if (!data->wMaxPacketSize)
+               goto err_put;
        dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
 
        data->bulk_out = bulk_out->bEndpointAddress;
index 1359b78..6cf22c2 100644 (file)
@@ -66,9 +66,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
        char            name[16];
        int             i, size;
 
-       if (!IS_ENABLED(CONFIG_HAS_DMA) ||
-           (!is_device_dma_capable(hcd->self.sysdev) &&
-            !hcd->localmem_pool))
+       if (hcd->localmem_pool || !hcd_uses_dma(hcd))
                return 0;
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -129,8 +127,7 @@ void *hcd_buffer_alloc(
                return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
 
        /* some USB hosts just use PIO */
-       if (!IS_ENABLED(CONFIG_HAS_DMA) ||
-           !is_device_dma_capable(bus->sysdev)) {
+       if (!hcd_uses_dma(hcd)) {
                *dma = ~(dma_addr_t) 0;
                return kmalloc(size, mem_flags);
        }
@@ -160,8 +157,7 @@ void hcd_buffer_free(
                return;
        }
 
-       if (!IS_ENABLED(CONFIG_HAS_DMA) ||
-           !is_device_dma_capable(bus->sysdev)) {
+       if (!hcd_uses_dma(hcd)) {
                kfree(addr);
                return;
        }
index 65de6f7..558890a 100644 (file)
@@ -193,9 +193,10 @@ int usb_register_dev(struct usb_interface *intf,
                intf->minor = minor;
                break;
        }
-       up_write(&minor_rwsem);
-       if (intf->minor < 0)
+       if (intf->minor < 0) {
+               up_write(&minor_rwsem);
                return -EXFULL;
+       }
 
        /* create a usb class device for this usb interface */
        snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
@@ -203,12 +204,11 @@ int usb_register_dev(struct usb_interface *intf,
                                      MKDEV(USB_MAJOR, minor), class_driver,
                                      "%s", kbasename(name));
        if (IS_ERR(intf->usb_dev)) {
-               down_write(&minor_rwsem);
                usb_minors[minor] = NULL;
                intf->minor = -1;
-               up_write(&minor_rwsem);
                retval = PTR_ERR(intf->usb_dev);
        }
+       up_write(&minor_rwsem);
        return retval;
 }
 EXPORT_SYMBOL_GPL(usb_register_dev);
@@ -234,12 +234,12 @@ void usb_deregister_dev(struct usb_interface *intf,
                return;
 
        dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
+       device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
 
        down_write(&minor_rwsem);
        usb_minors[intf->minor] = NULL;
        up_write(&minor_rwsem);
 
-       device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
        intf->usb_dev = NULL;
        intf->minor = -1;
        destroy_usb_class();
index 0343246..7537681 100644 (file)
@@ -216,17 +216,18 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                /* EHCI, OHCI */
                hcd->rsrc_start = pci_resource_start(dev, 0);
                hcd->rsrc_len = pci_resource_len(dev, 0);
-               if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
+               if (!devm_request_mem_region(&dev->dev, hcd->rsrc_start,
+                               hcd->rsrc_len, driver->description)) {
                        dev_dbg(&dev->dev, "controller already in use\n");
                        retval = -EBUSY;
                        goto put_hcd;
                }
-               hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+               hcd->regs = devm_ioremap_nocache(&dev->dev, hcd->rsrc_start,
+                               hcd->rsrc_len);
                if (hcd->regs == NULL) {
                        dev_dbg(&dev->dev, "error mapping memory\n");
                        retval = -EFAULT;
-                       goto release_mem_region;
+                       goto put_hcd;
                }
 
        } else {
@@ -240,8 +241,8 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
                        hcd->rsrc_start = pci_resource_start(dev, region);
                        hcd->rsrc_len = pci_resource_len(dev, region);
-                       if (request_region(hcd->rsrc_start, hcd->rsrc_len,
-                                       driver->description))
+                       if (devm_request_region(&dev->dev, hcd->rsrc_start,
+                                       hcd->rsrc_len, driver->description))
                                break;
                }
                if (region == PCI_ROM_RESOURCE) {
@@ -275,20 +276,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        }
 
        if (retval != 0)
-               goto unmap_registers;
+               goto put_hcd;
        device_wakeup_enable(hcd->self.controller);
 
        if (pci_dev_run_wake(dev))
                pm_runtime_put_noidle(&dev->dev);
        return retval;
 
-unmap_registers:
-       if (driver->flags & HCD_MEMORY) {
-               iounmap(hcd->regs);
-release_mem_region:
-               release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       } else
-               release_region(hcd->rsrc_start, hcd->rsrc_len);
 put_hcd:
        usb_put_hcd(hcd);
 disable_pci:
@@ -347,14 +341,6 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
                dev_set_drvdata(&dev->dev, NULL);
                up_read(&companions_rwsem);
        }
-
-       if (hcd->driver->flags & HCD_MEMORY) {
-               iounmap(hcd->regs);
-               release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       } else {
-               release_region(hcd->rsrc_start, hcd->rsrc_len);
-       }
-
        usb_put_hcd(hcd);
        pci_disable_device(dev);
 }
index 2ccbc2f..8592c03 100644 (file)
@@ -1412,7 +1412,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
        if (usb_endpoint_xfer_control(&urb->ep->desc)) {
                if (hcd->self.uses_pio_for_control)
                        return ret;
-               if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+               if (hcd_uses_dma(hcd)) {
                        if (is_vmalloc_addr(urb->setup_packet)) {
                                WARN_ONCE(1, "setup packet is not dma capable\n");
                                return -EAGAIN;
@@ -1446,7 +1446,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
        dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
        if (urb->transfer_buffer_length != 0
            && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
-               if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
+               if (hcd_uses_dma(hcd)) {
                        if (urb->num_sgs) {
                                int n;
 
index e844bb7..5adf489 100644 (file)
@@ -2218,14 +2218,14 @@ int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
                                (struct usb_cdc_dmm_desc *)buffer;
                        break;
                case USB_CDC_MDLM_TYPE:
-                       if (elength < sizeof(struct usb_cdc_mdlm_desc *))
+                       if (elength < sizeof(struct usb_cdc_mdlm_desc))
                                goto next_desc;
                        if (desc)
                                return -EINVAL;
                        desc = (struct usb_cdc_mdlm_desc *)buffer;
                        break;
                case USB_CDC_MDLM_DETAIL_TYPE:
-                       if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
+                       if (elength < sizeof(struct usb_cdc_mdlm_detail_desc))
                                goto next_desc;
                        if (detail)
                                return -EINVAL;
index ee144ff..111787a 100644 (file)
@@ -4608,7 +4608,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        buf = urb->transfer_buffer;
 
-       if (hcd->self.uses_dma) {
+       if (hcd_uses_dma(hcd)) {
                if (!buf && (urb->transfer_dma & 3)) {
                        dev_err(hsotg->dev,
                                "%s: unaligned transfer with no transfer_buffer",
index 9118b42..76883ff 100644 (file)
@@ -1976,6 +1976,7 @@ void composite_disconnect(struct usb_gadget *gadget)
         * disconnect callbacks?
         */
        spin_lock_irqsave(&cdev->lock, flags);
+       cdev->suspended = 0;
        if (cdev->config)
                reset_config(cdev);
        if (cdev->driver->disconnect)
index 29cc569..7c96c46 100644 (file)
@@ -261,7 +261,7 @@ struct fsg_common;
 struct fsg_common {
        struct usb_gadget       *gadget;
        struct usb_composite_dev *cdev;
-       struct fsg_dev          *fsg, *new_fsg;
+       struct fsg_dev          *fsg;
        wait_queue_head_t       io_wait;
        wait_queue_head_t       fsg_wait;
 
@@ -290,6 +290,7 @@ struct fsg_common {
        unsigned int            bulk_out_maxpacket;
        enum fsg_state          state;          /* For exception handling */
        unsigned int            exception_req_tag;
+       void                    *exception_arg;
 
        enum data_direction     data_dir;
        u32                     data_size;
@@ -391,7 +392,8 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
 
 /* These routines may be called in process context or in_irq */
 
-static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
+static void __raise_exception(struct fsg_common *common, enum fsg_state new_state,
+                             void *arg)
 {
        unsigned long           flags;
 
@@ -404,6 +406,7 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
        if (common->state <= new_state) {
                common->exception_req_tag = common->ep0_req_tag;
                common->state = new_state;
+               common->exception_arg = arg;
                if (common->thread_task)
                        send_sig_info(SIGUSR1, SEND_SIG_PRIV,
                                      common->thread_task);
@@ -411,6 +414,10 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
        spin_unlock_irqrestore(&common->lock, flags);
 }
 
+static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
+{
+       __raise_exception(common, new_state, NULL);
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -2285,16 +2292,16 @@ reset:
 static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
        struct fsg_dev *fsg = fsg_from_func(f);
-       fsg->common->new_fsg = fsg;
-       raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+
+       __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, fsg);
        return USB_GADGET_DELAYED_STATUS;
 }
 
 static void fsg_disable(struct usb_function *f)
 {
        struct fsg_dev *fsg = fsg_from_func(f);
-       fsg->common->new_fsg = NULL;
-       raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+
+       __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, NULL);
 }
 
 
@@ -2307,6 +2314,7 @@ static void handle_exception(struct fsg_common *common)
        enum fsg_state          old_state;
        struct fsg_lun          *curlun;
        unsigned int            exception_req_tag;
+       struct fsg_dev          *new_fsg;
 
        /*
         * Clear the existing signals.  Anything but SIGUSR1 is converted
@@ -2360,6 +2368,7 @@ static void handle_exception(struct fsg_common *common)
        common->next_buffhd_to_fill = &common->buffhds[0];
        common->next_buffhd_to_drain = &common->buffhds[0];
        exception_req_tag = common->exception_req_tag;
+       new_fsg = common->exception_arg;
        old_state = common->state;
        common->state = FSG_STATE_NORMAL;
 
@@ -2413,8 +2422,8 @@ static void handle_exception(struct fsg_common *common)
                break;
 
        case FSG_STATE_CONFIG_CHANGE:
-               do_set_interface(common, common->new_fsg);
-               if (common->new_fsg)
+               do_set_interface(common, new_fsg);
+               if (new_fsg)
                        usb_composite_setup_continue(common->cdev);
                break;
 
@@ -2989,8 +2998,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(fsg, "unbind\n");
        if (fsg->common->fsg == fsg) {
-               fsg->common->new_fsg = NULL;
-               raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+               __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, NULL);
                /* FIXME: make interruptible or killable somehow? */
                wait_event(common->fsg_wait, common->fsg != fsg);
        }
index d354036..d7e6116 100644 (file)
@@ -45,7 +45,7 @@ config USB_AT91
 
 config USB_LPC32XX
        tristate "LPC32XX USB Peripheral Controller"
-       depends on ARCH_LPC32XX || COMPILE_TEST
+       depends on ARCH_LPC32XX
        depends on I2C
        select USB_ISP1301
        help
index defe04d..c65aed3 100644 (file)
@@ -2264,7 +2264,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
                default:
                        break;
                }
-
+               break;
 
        case USB_REQ_SET_ADDRESS:
                if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
index 87062d2..1f4c3fb 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/sys_soc.h>
 #include <linux/uaccess.h>
 #include <linux/usb/ch9.h>
@@ -2450,9 +2451,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
        if (usb3->forced_b_device)
                return -EBUSY;
 
-       if (!strncmp(buf, "host", strlen("host")))
+       if (sysfs_streq(buf, "host"))
                new_mode_is_host = true;
-       else if (!strncmp(buf, "peripheral", strlen("peripheral")))
+       else if (sysfs_streq(buf, "peripheral"))
                new_mode_is_host = false;
        else
                return -EINVAL;
index 77cc36e..0dbfa5c 100644 (file)
@@ -1629,6 +1629,10 @@ static int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        /* see what we found out */
                        temp = check_reset_complete(fotg210, wIndex, status_reg,
                                        fotg210_readl(fotg210, status_reg));
+
+                       /* restart schedule */
+                       fotg210->command |= CMD_RUN;
+                       fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
                }
 
                if (!(temp & (PORT_RESUME|PORT_RESET))) {
index b457fda..1fe3dee 100644 (file)
@@ -419,8 +419,7 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
  * other cases where the next software may expect clean state from the
  * "firmware".  this is bus-neutral, unlike shutdown() methods.
  */
-static void
-ohci_shutdown (struct usb_hcd *hcd)
+static void _ohci_shutdown(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci;
 
@@ -436,6 +435,16 @@ ohci_shutdown (struct usb_hcd *hcd)
        ohci->rh_state = OHCI_RH_HALTED;
 }
 
+static void ohci_shutdown(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+       _ohci_shutdown(hcd);
+       spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -760,7 +769,7 @@ static void io_watchdog_func(struct timer_list *t)
  died:
                        usb_hc_died(ohci_to_hcd(ohci));
                        ohci_dump(ohci);
-                       ohci_shutdown(ohci_to_hcd(ohci));
+                       _ohci_shutdown(ohci_to_hcd(ohci));
                        goto done;
                } else {
                        /* No write back because the done queue was empty */
index 8616c52..2b0ccd1 100644 (file)
@@ -104,7 +104,7 @@ static int xhci_rcar_is_gen2(struct device *dev)
        return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
                of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
                of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
-               of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
+               of_device_is_compatible(node, "renesas,rcar-gen2-xhci");
 }
 
 static int xhci_rcar_is_gen3(struct device *dev)
index dafc659..2ff7c91 100644 (file)
@@ -1194,6 +1194,16 @@ static int tegra_xusb_probe(struct platform_device *pdev)
 
        tegra_xusb_config(tegra, regs);
 
+       /*
+        * The XUSB Falcon microcontroller can only address 40 bits, so set
+        * the DMA mask accordingly.
+        */
+       err = dma_set_mask_and_coherent(tegra->dev, DMA_BIT_MASK(40));
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
+               goto put_rpm;
+       }
+
        err = tegra_xusb_load_firmware(tegra);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to load firmware: %d\n", err);
index c1582fb..38e920a 100644 (file)
@@ -968,6 +968,11 @@ static const struct usb_device_id option_ids[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
        { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
 
+       /* Motorola devices */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2a70, 0xff, 0xff, 0xff) },    /* mdm6600 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2e0a, 0xff, 0xff, 0xff) },    /* mdm9600 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x4281, 0x0a, 0x00, 0xfc) },    /* mdm ram dl */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x900e, 0xff, 0xff, 0xff) },    /* mdm qc dl */
 
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
@@ -1549,6 +1554,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff),  /* Telewell TW-LTE 4G v2 */
          .driver_info = RSVD(2) },
        { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) },    /* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0x00, 0x00) }, /* ZTE MF871A */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
@@ -1952,11 +1958,15 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(4) },
        { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff),                     /* D-Link DWM-222 */
          .driver_info = RSVD(4) },
+       { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e3d, 0xff),                     /* D-Link DWM-222 A2 */
+         .driver_info = RSVD(4) },
        { 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_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) },    /* D-Link DWM-156/A3 */
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff),                     /* Olicard 600 */
          .driver_info = RSVD(4) },
+       { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2060, 0xff),                     /* BroadMobi BM818 */
+         .driver_info = RSVD(4) },
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                   /* OLICARD300 - MT6225 */
        { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
        { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
index cc794e2..1d9ce9c 100644 (file)
@@ -38,7 +38,7 @@ MODULE_LICENSE("GPL");
 
 static int auto_delink_en = 1;
 module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
+MODULE_PARM_DESC(auto_delink_en, "auto delink mode (0=firmware, 1=software [default])");
 
 #ifdef CONFIG_REALTEK_AUTOPM
 static int ss_en = 1;
@@ -996,12 +996,15 @@ static int init_realtek_cr(struct us_data *us)
                        goto INIT_FAIL;
        }
 
-       if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
-           CHECK_FW_VER(chip, 0x5901))
-               SET_AUTO_DELINK(chip);
-       if (STATUS_LEN(chip) == 16) {
-               if (SUPPORT_AUTO_DELINK(chip))
+       if (CHECK_PID(chip, 0x0138) || CHECK_PID(chip, 0x0158) ||
+           CHECK_PID(chip, 0x0159)) {
+               if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
+                               CHECK_FW_VER(chip, 0x5901))
                        SET_AUTO_DELINK(chip);
+               if (STATUS_LEN(chip) == 16) {
+                       if (SUPPORT_AUTO_DELINK(chip))
+                               SET_AUTO_DELINK(chip);
+               }
        }
 #ifdef CONFIG_REALTEK_AUTOPM
        if (ss_en)
index ea0d27a..1cd9b63 100644 (file)
@@ -2100,7 +2100,7 @@ UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,
                US_FL_IGNORE_RESIDUE ),
 
 /* Reported by Michael Büsch <m@bues.ch> */
-UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0116,
+UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0117,
                "JMicron",
                "USB to ATA/ATAPI Bridge",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
index 15abe1d..bcfdb55 100644 (file)
@@ -1446,7 +1446,7 @@ static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo,
                                else if ((pdo_min_voltage(pdo[i]) ==
                                          pdo_min_voltage(pdo[i - 1])) &&
                                         (pdo_max_voltage(pdo[i]) ==
-                                         pdo_min_voltage(pdo[i - 1])))
+                                         pdo_max_voltage(pdo[i - 1])))
                                        return PDO_ERR_DUPE_PDO;
                                break;
                        /*
index 054391f..ad830ab 100644 (file)
@@ -650,12 +650,13 @@ unpin_exit:
 }
 
 static long vfio_sync_unpin(struct vfio_dma *dma, struct vfio_domain *domain,
-                               struct list_head *regions)
+                           struct list_head *regions,
+                           struct iommu_iotlb_gather *iotlb_gather)
 {
        long unlocked = 0;
        struct vfio_regions *entry, *next;
 
-       iommu_tlb_sync(domain->domain);
+       iommu_tlb_sync(domain->domain, iotlb_gather);
 
        list_for_each_entry_safe(entry, next, regions, list) {
                unlocked += vfio_unpin_pages_remote(dma,
@@ -685,18 +686,19 @@ static size_t unmap_unpin_fast(struct vfio_domain *domain,
                               struct vfio_dma *dma, dma_addr_t *iova,
                               size_t len, phys_addr_t phys, long *unlocked,
                               struct list_head *unmapped_list,
-                              int *unmapped_cnt)
+                              int *unmapped_cnt,
+                              struct iommu_iotlb_gather *iotlb_gather)
 {
        size_t unmapped = 0;
        struct vfio_regions *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 
        if (entry) {
-               unmapped = iommu_unmap_fast(domain->domain, *iova, len);
+               unmapped = iommu_unmap_fast(domain->domain, *iova, len,
+                                           iotlb_gather);
 
                if (!unmapped) {
                        kfree(entry);
                } else {
-                       iommu_tlb_range_add(domain->domain, *iova, unmapped);
                        entry->iova = *iova;
                        entry->phys = phys;
                        entry->len  = unmapped;
@@ -712,8 +714,8 @@ static size_t unmap_unpin_fast(struct vfio_domain *domain,
         * or in case of errors.
         */
        if (*unmapped_cnt >= VFIO_IOMMU_TLB_SYNC_MAX || !unmapped) {
-               *unlocked += vfio_sync_unpin(dma, domain,
-                                            unmapped_list);
+               *unlocked += vfio_sync_unpin(dma, domain, unmapped_list,
+                                            iotlb_gather);
                *unmapped_cnt = 0;
        }
 
@@ -744,6 +746,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
        dma_addr_t iova = dma->iova, end = dma->iova + dma->size;
        struct vfio_domain *domain, *d;
        LIST_HEAD(unmapped_region_list);
+       struct iommu_iotlb_gather iotlb_gather;
        int unmapped_region_cnt = 0;
        long unlocked = 0;
 
@@ -768,6 +771,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
                cond_resched();
        }
 
+       iommu_iotlb_gather_init(&iotlb_gather);
        while (iova < end) {
                size_t unmapped, len;
                phys_addr_t phys, next;
@@ -796,7 +800,8 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
                 */
                unmapped = unmap_unpin_fast(domain, dma, &iova, len, phys,
                                            &unlocked, &unmapped_region_list,
-                                           &unmapped_region_cnt);
+                                           &unmapped_region_cnt,
+                                           &iotlb_gather);
                if (!unmapped) {
                        unmapped = unmap_unpin_slow(domain, dma, &iova, len,
                                                    phys, &unlocked);
@@ -807,8 +812,10 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma,
 
        dma->iommu_mapped = false;
 
-       if (unmapped_region_cnt)
-               unlocked += vfio_sync_unpin(dma, domain, &unmapped_region_list);
+       if (unmapped_region_cnt) {
+               unlocked += vfio_sync_unpin(dma, domain, &unmapped_region_list,
+                                           &iotlb_gather);
+       }
 
        if (do_accounting) {
                vfio_lock_acct(dma, -unlocked, true);
index 9e90e96..7804869 100644 (file)
  * Using this limit prevents one virtqueue from starving others. */
 #define VHOST_TEST_WEIGHT 0x80000
 
+/* Max number of packets transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with
+ * pkts.
+ */
+#define VHOST_TEST_PKT_WEIGHT 256
+
 enum {
        VHOST_TEST_VQ = 0,
        VHOST_TEST_VQ_MAX = 1,
@@ -80,10 +86,8 @@ static void handle_vq(struct vhost_test *n)
                }
                vhost_add_used_and_signal(&n->dev, vq, head, 0);
                total_len += len;
-               if (unlikely(total_len >= VHOST_TEST_WEIGHT)) {
-                       vhost_poll_queue(&vq->poll);
+               if (unlikely(vhost_exceeds_weight(vq, 0, total_len)))
                        break;
-               }
        }
 
        mutex_unlock(&vq->mutex);
@@ -115,7 +119,8 @@ static int vhost_test_open(struct inode *inode, struct file *f)
        dev = &n->dev;
        vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ];
        n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
-       vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX);
+       vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX, UIO_MAXIOV,
+                      VHOST_TEST_PKT_WEIGHT, VHOST_TEST_WEIGHT);
 
        f->private_data = n;
 
index 0536f85..36ca2cf 100644 (file)
@@ -203,7 +203,6 @@ EXPORT_SYMBOL_GPL(vhost_poll_init);
 int vhost_poll_start(struct vhost_poll *poll, struct file *file)
 {
        __poll_t mask;
-       int ret = 0;
 
        if (poll->wqh)
                return 0;
@@ -213,10 +212,10 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file)
                vhost_poll_wakeup(&poll->wait, 0, 0, poll_to_key(mask));
        if (mask & EPOLLERR) {
                vhost_poll_stop(poll);
-               ret = -EINVAL;
+               return -EINVAL;
        }
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(vhost_poll_start);
 
@@ -298,160 +297,6 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
                __vhost_vq_meta_reset(d->vqs[i]);
 }
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-static void vhost_map_unprefetch(struct vhost_map *map)
-{
-       kfree(map->pages);
-       map->pages = NULL;
-       map->npages = 0;
-       map->addr = NULL;
-}
-
-static void vhost_uninit_vq_maps(struct vhost_virtqueue *vq)
-{
-       struct vhost_map *map[VHOST_NUM_ADDRS];
-       int i;
-
-       spin_lock(&vq->mmu_lock);
-       for (i = 0; i < VHOST_NUM_ADDRS; i++) {
-               map[i] = rcu_dereference_protected(vq->maps[i],
-                                 lockdep_is_held(&vq->mmu_lock));
-               if (map[i])
-                       rcu_assign_pointer(vq->maps[i], NULL);
-       }
-       spin_unlock(&vq->mmu_lock);
-
-       synchronize_rcu();
-
-       for (i = 0; i < VHOST_NUM_ADDRS; i++)
-               if (map[i])
-                       vhost_map_unprefetch(map[i]);
-
-}
-
-static void vhost_reset_vq_maps(struct vhost_virtqueue *vq)
-{
-       int i;
-
-       vhost_uninit_vq_maps(vq);
-       for (i = 0; i < VHOST_NUM_ADDRS; i++)
-               vq->uaddrs[i].size = 0;
-}
-
-static bool vhost_map_range_overlap(struct vhost_uaddr *uaddr,
-                                    unsigned long start,
-                                    unsigned long end)
-{
-       if (unlikely(!uaddr->size))
-               return false;
-
-       return !(end < uaddr->uaddr || start > uaddr->uaddr - 1 + uaddr->size);
-}
-
-static void vhost_invalidate_vq_start(struct vhost_virtqueue *vq,
-                                     int index,
-                                     unsigned long start,
-                                     unsigned long end)
-{
-       struct vhost_uaddr *uaddr = &vq->uaddrs[index];
-       struct vhost_map *map;
-       int i;
-
-       if (!vhost_map_range_overlap(uaddr, start, end))
-               return;
-
-       spin_lock(&vq->mmu_lock);
-       ++vq->invalidate_count;
-
-       map = rcu_dereference_protected(vq->maps[index],
-                                       lockdep_is_held(&vq->mmu_lock));
-       if (map) {
-               if (uaddr->write) {
-                       for (i = 0; i < map->npages; i++)
-                               set_page_dirty(map->pages[i]);
-               }
-               rcu_assign_pointer(vq->maps[index], NULL);
-       }
-       spin_unlock(&vq->mmu_lock);
-
-       if (map) {
-               synchronize_rcu();
-               vhost_map_unprefetch(map);
-       }
-}
-
-static void vhost_invalidate_vq_end(struct vhost_virtqueue *vq,
-                                   int index,
-                                   unsigned long start,
-                                   unsigned long end)
-{
-       if (!vhost_map_range_overlap(&vq->uaddrs[index], start, end))
-               return;
-
-       spin_lock(&vq->mmu_lock);
-       --vq->invalidate_count;
-       spin_unlock(&vq->mmu_lock);
-}
-
-static int vhost_invalidate_range_start(struct mmu_notifier *mn,
-                                       const struct mmu_notifier_range *range)
-{
-       struct vhost_dev *dev = container_of(mn, struct vhost_dev,
-                                            mmu_notifier);
-       int i, j;
-
-       if (!mmu_notifier_range_blockable(range))
-               return -EAGAIN;
-
-       for (i = 0; i < dev->nvqs; i++) {
-               struct vhost_virtqueue *vq = dev->vqs[i];
-
-               for (j = 0; j < VHOST_NUM_ADDRS; j++)
-                       vhost_invalidate_vq_start(vq, j,
-                                                 range->start,
-                                                 range->end);
-       }
-
-       return 0;
-}
-
-static void vhost_invalidate_range_end(struct mmu_notifier *mn,
-                                      const struct mmu_notifier_range *range)
-{
-       struct vhost_dev *dev = container_of(mn, struct vhost_dev,
-                                            mmu_notifier);
-       int i, j;
-
-       for (i = 0; i < dev->nvqs; i++) {
-               struct vhost_virtqueue *vq = dev->vqs[i];
-
-               for (j = 0; j < VHOST_NUM_ADDRS; j++)
-                       vhost_invalidate_vq_end(vq, j,
-                                               range->start,
-                                               range->end);
-       }
-}
-
-static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
-       .invalidate_range_start = vhost_invalidate_range_start,
-       .invalidate_range_end = vhost_invalidate_range_end,
-};
-
-static void vhost_init_maps(struct vhost_dev *dev)
-{
-       struct vhost_virtqueue *vq;
-       int i, j;
-
-       dev->mmu_notifier.ops = &vhost_mmu_notifier_ops;
-
-       for (i = 0; i < dev->nvqs; ++i) {
-               vq = dev->vqs[i];
-               for (j = 0; j < VHOST_NUM_ADDRS; j++)
-                       RCU_INIT_POINTER(vq->maps[j], NULL);
-       }
-}
-#endif
-
 static void vhost_vq_reset(struct vhost_dev *dev,
                           struct vhost_virtqueue *vq)
 {
@@ -480,11 +325,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->busyloop_timeout = 0;
        vq->umem = NULL;
        vq->iotlb = NULL;
-       vq->invalidate_count = 0;
        __vhost_vq_meta_reset(vq);
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       vhost_reset_vq_maps(vq);
-#endif
 }
 
 static int vhost_worker(void *data)
@@ -634,9 +475,7 @@ void vhost_dev_init(struct vhost_dev *dev,
        INIT_LIST_HEAD(&dev->read_list);
        INIT_LIST_HEAD(&dev->pending_list);
        spin_lock_init(&dev->iotlb_lock);
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       vhost_init_maps(dev);
-#endif
+
 
        for (i = 0; i < dev->nvqs; ++i) {
                vq = dev->vqs[i];
@@ -645,7 +484,6 @@ void vhost_dev_init(struct vhost_dev *dev,
                vq->heads = NULL;
                vq->dev = dev;
                mutex_init(&vq->mutex);
-               spin_lock_init(&vq->mmu_lock);
                vhost_vq_reset(dev, vq);
                if (vq->handle_kick)
                        vhost_poll_init(&vq->poll, vq->handle_kick,
@@ -725,18 +563,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
        if (err)
                goto err_cgroup;
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       err = mmu_notifier_register(&dev->mmu_notifier, dev->mm);
-       if (err)
-               goto err_mmu_notifier;
-#endif
-
        return 0;
-
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-err_mmu_notifier:
-       vhost_dev_free_iovecs(dev);
-#endif
 err_cgroup:
        kthread_stop(worker);
        dev->worker = NULL;
@@ -827,107 +654,6 @@ static void vhost_clear_msg(struct vhost_dev *dev)
        spin_unlock(&dev->iotlb_lock);
 }
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-static void vhost_setup_uaddr(struct vhost_virtqueue *vq,
-                             int index, unsigned long uaddr,
-                             size_t size, bool write)
-{
-       struct vhost_uaddr *addr = &vq->uaddrs[index];
-
-       addr->uaddr = uaddr;
-       addr->size = size;
-       addr->write = write;
-}
-
-static void vhost_setup_vq_uaddr(struct vhost_virtqueue *vq)
-{
-       vhost_setup_uaddr(vq, VHOST_ADDR_DESC,
-                         (unsigned long)vq->desc,
-                         vhost_get_desc_size(vq, vq->num),
-                         false);
-       vhost_setup_uaddr(vq, VHOST_ADDR_AVAIL,
-                         (unsigned long)vq->avail,
-                         vhost_get_avail_size(vq, vq->num),
-                         false);
-       vhost_setup_uaddr(vq, VHOST_ADDR_USED,
-                         (unsigned long)vq->used,
-                         vhost_get_used_size(vq, vq->num),
-                         true);
-}
-
-static int vhost_map_prefetch(struct vhost_virtqueue *vq,
-                              int index)
-{
-       struct vhost_map *map;
-       struct vhost_uaddr *uaddr = &vq->uaddrs[index];
-       struct page **pages;
-       int npages = DIV_ROUND_UP(uaddr->size, PAGE_SIZE);
-       int npinned;
-       void *vaddr, *v;
-       int err;
-       int i;
-
-       spin_lock(&vq->mmu_lock);
-
-       err = -EFAULT;
-       if (vq->invalidate_count)
-               goto err;
-
-       err = -ENOMEM;
-       map = kmalloc(sizeof(*map), GFP_ATOMIC);
-       if (!map)
-               goto err;
-
-       pages = kmalloc_array(npages, sizeof(struct page *), GFP_ATOMIC);
-       if (!pages)
-               goto err_pages;
-
-       err = EFAULT;
-       npinned = __get_user_pages_fast(uaddr->uaddr, npages,
-                                       uaddr->write, pages);
-       if (npinned > 0)
-               release_pages(pages, npinned);
-       if (npinned != npages)
-               goto err_gup;
-
-       for (i = 0; i < npinned; i++)
-               if (PageHighMem(pages[i]))
-                       goto err_gup;
-
-       vaddr = v = page_address(pages[0]);
-
-       /* For simplicity, fallback to userspace address if VA is not
-        * contigious.
-        */
-       for (i = 1; i < npinned; i++) {
-               v += PAGE_SIZE;
-               if (v != page_address(pages[i]))
-                       goto err_gup;
-       }
-
-       map->addr = vaddr + (uaddr->uaddr & (PAGE_SIZE - 1));
-       map->npages = npages;
-       map->pages = pages;
-
-       rcu_assign_pointer(vq->maps[index], map);
-       /* No need for a synchronize_rcu(). This function should be
-        * called by dev->worker so we are serialized with all
-        * readers.
-        */
-       spin_unlock(&vq->mmu_lock);
-
-       return 0;
-
-err_gup:
-       kfree(pages);
-err_pages:
-       kfree(map);
-err:
-       spin_unlock(&vq->mmu_lock);
-       return err;
-}
-#endif
-
 void vhost_dev_cleanup(struct vhost_dev *dev)
 {
        int i;
@@ -957,16 +683,8 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
                kthread_stop(dev->worker);
                dev->worker = NULL;
        }
-       if (dev->mm) {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-               mmu_notifier_unregister(&dev->mmu_notifier, dev->mm);
-#endif
+       if (dev->mm)
                mmput(dev->mm);
-       }
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       for (i = 0; i < dev->nvqs; i++)
-               vhost_uninit_vq_maps(dev->vqs[i]);
-#endif
        dev->mm = NULL;
 }
 EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
@@ -1195,26 +913,6 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
 
 static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_used *used;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
-               if (likely(map)) {
-                       used = map->addr;
-                       *((__virtio16 *)&used->ring[vq->num]) =
-                               cpu_to_vhost16(vq, vq->avail_idx);
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
                              vhost_avail_event(vq));
 }
@@ -1223,27 +921,6 @@ static inline int vhost_put_used(struct vhost_virtqueue *vq,
                                 struct vring_used_elem *head, int idx,
                                 int count)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_used *used;
-       size_t size;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
-               if (likely(map)) {
-                       used = map->addr;
-                       size = count * sizeof(*head);
-                       memcpy(used->ring + idx, head, size);
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_copy_to_user(vq, vq->used->ring + idx, head,
                                  count * sizeof(*head));
 }
@@ -1251,25 +928,6 @@ static inline int vhost_put_used(struct vhost_virtqueue *vq,
 static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
 
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_used *used;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
-               if (likely(map)) {
-                       used = map->addr;
-                       used->flags = cpu_to_vhost16(vq, vq->used_flags);
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
                              &vq->used->flags);
 }
@@ -1277,25 +935,6 @@ static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
 static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
 
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_used *used;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
-               if (likely(map)) {
-                       used = map->addr;
-                       used->idx = cpu_to_vhost16(vq, vq->last_used_idx);
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
                              &vq->used->idx);
 }
@@ -1341,50 +980,12 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
 static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
                                      __virtio16 *idx)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_avail *avail;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
-               if (likely(map)) {
-                       avail = map->addr;
-                       *idx = avail->idx;
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_get_avail(vq, *idx, &vq->avail->idx);
 }
 
 static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
                                       __virtio16 *head, int idx)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_avail *avail;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
-               if (likely(map)) {
-                       avail = map->addr;
-                       *head = avail->ring[idx & (vq->num - 1)];
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_get_avail(vq, *head,
                               &vq->avail->ring[idx & (vq->num - 1)]);
 }
@@ -1392,98 +993,24 @@ static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
 static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
                                        __virtio16 *flags)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_avail *avail;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
-               if (likely(map)) {
-                       avail = map->addr;
-                       *flags = avail->flags;
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_get_avail(vq, *flags, &vq->avail->flags);
 }
 
 static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
                                       __virtio16 *event)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_avail *avail;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-               map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
-               if (likely(map)) {
-                       avail = map->addr;
-                       *event = (__virtio16)avail->ring[vq->num];
-                       rcu_read_unlock();
-                       return 0;
-               }
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_get_avail(vq, *event, vhost_used_event(vq));
 }
 
 static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
                                     __virtio16 *idx)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_used *used;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
-               if (likely(map)) {
-                       used = map->addr;
-                       *idx = used->idx;
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_get_used(vq, *idx, &vq->used->idx);
 }
 
 static inline int vhost_get_desc(struct vhost_virtqueue *vq,
                                 struct vring_desc *desc, int idx)
 {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       struct vhost_map *map;
-       struct vring_desc *d;
-
-       if (!vq->iotlb) {
-               rcu_read_lock();
-
-               map = rcu_dereference(vq->maps[VHOST_ADDR_DESC]);
-               if (likely(map)) {
-                       d = map->addr;
-                       *desc = *(d + idx);
-                       rcu_read_unlock();
-                       return 0;
-               }
-
-               rcu_read_unlock();
-       }
-#endif
-
        return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
 }
 
@@ -1824,32 +1351,12 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
        return true;
 }
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-static void vhost_vq_map_prefetch(struct vhost_virtqueue *vq)
-{
-       struct vhost_map __rcu *map;
-       int i;
-
-       for (i = 0; i < VHOST_NUM_ADDRS; i++) {
-               rcu_read_lock();
-               map = rcu_dereference(vq->maps[i]);
-               rcu_read_unlock();
-               if (unlikely(!map))
-                       vhost_map_prefetch(vq, i);
-       }
-}
-#endif
-
 int vq_meta_prefetch(struct vhost_virtqueue *vq)
 {
        unsigned int num = vq->num;
 
-       if (!vq->iotlb) {
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-               vhost_vq_map_prefetch(vq);
-#endif
+       if (!vq->iotlb)
                return 1;
-       }
 
        return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
                               vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
@@ -2060,16 +1567,6 @@ static long vhost_vring_set_num_addr(struct vhost_dev *d,
 
        mutex_lock(&vq->mutex);
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       /* Unregister MMU notifer to allow invalidation callback
-        * can access vq->uaddrs[] without holding a lock.
-        */
-       if (d->mm)
-               mmu_notifier_unregister(&d->mmu_notifier, d->mm);
-
-       vhost_uninit_vq_maps(vq);
-#endif
-
        switch (ioctl) {
        case VHOST_SET_VRING_NUM:
                r = vhost_vring_set_num(d, vq, argp);
@@ -2081,13 +1578,6 @@ static long vhost_vring_set_num_addr(struct vhost_dev *d,
                BUG();
        }
 
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       vhost_setup_vq_uaddr(vq);
-
-       if (d->mm)
-               mmu_notifier_register(&d->mmu_notifier, d->mm);
-#endif
-
        mutex_unlock(&vq->mutex);
 
        return r;
@@ -2688,7 +2178,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
                /* If this is an input descriptor, increment that count. */
                if (access == VHOST_ACCESS_WO) {
                        *in_num += ret;
-                       if (unlikely(log)) {
+                       if (unlikely(log && ret)) {
                                log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
                                log[*log_num].len = vhost32_to_cpu(vq, desc.len);
                                ++*log_num;
@@ -2829,7 +2319,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                        /* If this is an input descriptor,
                         * increment that count. */
                        *in_num += ret;
-                       if (unlikely(log)) {
+                       if (unlikely(log && ret)) {
                                log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
                                log[*log_num].len = vhost32_to_cpu(vq, desc.len);
                                ++*log_num;
index 42a8c2a..e9ed272 100644 (file)
@@ -12,9 +12,6 @@
 #include <linux/virtio_config.h>
 #include <linux/virtio_ring.h>
 #include <linux/atomic.h>
-#include <linux/pagemap.h>
-#include <linux/mmu_notifier.h>
-#include <asm/cacheflush.h>
 
 struct vhost_work;
 typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -83,24 +80,6 @@ enum vhost_uaddr_type {
        VHOST_NUM_ADDRS = 3,
 };
 
-struct vhost_map {
-       int npages;
-       void *addr;
-       struct page **pages;
-};
-
-struct vhost_uaddr {
-       unsigned long uaddr;
-       size_t size;
-       bool write;
-};
-
-#if defined(CONFIG_MMU_NOTIFIER) && ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 0
-#define VHOST_ARCH_CAN_ACCEL_UACCESS 0
-#else
-#define VHOST_ARCH_CAN_ACCEL_UACCESS 0
-#endif
-
 /* The virtqueue structure describes a queue attached to a device. */
 struct vhost_virtqueue {
        struct vhost_dev *dev;
@@ -111,22 +90,7 @@ struct vhost_virtqueue {
        struct vring_desc __user *desc;
        struct vring_avail __user *avail;
        struct vring_used __user *used;
-
-#if VHOST_ARCH_CAN_ACCEL_UACCESS
-       /* Read by memory accessors, modified by meta data
-        * prefetching, MMU notifier and vring ioctl().
-        * Synchonrized through mmu_lock (writers) and RCU (writers
-        * and readers).
-        */
-       struct vhost_map __rcu *maps[VHOST_NUM_ADDRS];
-       /* Read by MMU notifier, modified by vring ioctl(),
-        * synchronized through MMU notifier
-        * registering/unregistering.
-        */
-       struct vhost_uaddr uaddrs[VHOST_NUM_ADDRS];
-#endif
        const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
-
        struct file *kick;
        struct eventfd_ctx *call_ctx;
        struct eventfd_ctx *error_ctx;
@@ -181,8 +145,6 @@ struct vhost_virtqueue {
        bool user_be;
 #endif
        u32 busyloop_timeout;
-       spinlock_t mmu_lock;
-       int invalidate_count;
 };
 
 struct vhost_msg_node {
@@ -196,9 +158,6 @@ struct vhost_msg_node {
 
 struct vhost_dev {
        struct mm_struct *mm;
-#ifdef CONFIG_MMU_NOTIFIER
-       struct mmu_notifier mmu_notifier;
-#endif
        struct mutex mutex;
        struct vhost_virtqueue **vqs;
        int nvqs;
index 92f23e3..7cacae5 100644 (file)
@@ -858,6 +858,7 @@ static void acornfb_parse_dram(char *opt)
                case 'M':
                case 'm':
                        size *= 1024;
+                       /* Fall through */
                case 'K':
                case 'k':
                        size *= 1024;
index fc9dfb0..51f5d1c 100644 (file)
@@ -763,17 +763,17 @@ static void tt_get_par(struct atafb_par *par)
 {
        unsigned long addr;
        par->hw.tt.mode = shifter_tt.tt_shiftmode;
-       par->hw.tt.sync = shifter.syncmode;
-       addr = ((shifter.bas_hi & 0xff) << 16) |
-              ((shifter.bas_md & 0xff) << 8)  |
-              ((shifter.bas_lo & 0xff));
+       par->hw.tt.sync = shifter_st.syncmode;
+       addr = ((shifter_st.bas_hi & 0xff) << 16) |
+              ((shifter_st.bas_md & 0xff) << 8)  |
+              ((shifter_st.bas_lo & 0xff));
        par->screen_base = atari_stram_to_virt(addr);
 }
 
 static void tt_set_par(struct atafb_par *par)
 {
        shifter_tt.tt_shiftmode = par->hw.tt.mode;
-       shifter.syncmode = par->hw.tt.sync;
+       shifter_st.syncmode = par->hw.tt.sync;
        /* only set screen_base if really necessary */
        if (current_par.screen_base != par->screen_base)
                fbhw->set_screen_base(par->screen_base);
@@ -1543,7 +1543,7 @@ static void falcon_get_par(struct atafb_par *par)
        hw->f_shift = videl.f_shift;
        hw->vid_control = videl.control;
        hw->vid_mode = videl.mode;
-       hw->sync = shifter.syncmode & 0x1;
+       hw->sync = shifter_st.syncmode & 0x1;
        hw->xoffset = videl.xoffset & 0xf;
        hw->hht = videl.hht;
        hw->hbb = videl.hbb;
@@ -1558,9 +1558,9 @@ static void falcon_get_par(struct atafb_par *par)
        hw->vde = videl.vde;
        hw->vss = videl.vss;
 
-       addr = (shifter.bas_hi & 0xff) << 16 |
-              (shifter.bas_md & 0xff) << 8  |
-              (shifter.bas_lo & 0xff);
+       addr = (shifter_st.bas_hi & 0xff) << 16 |
+              (shifter_st.bas_md & 0xff) << 8  |
+              (shifter_st.bas_lo & 0xff);
        par->screen_base = atari_stram_to_virt(addr);
 
        /* derived parameters */
@@ -1605,7 +1605,7 @@ static irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
                        /* Turn off external clocks. Read sets all output bits to 1. */
                        *(volatile unsigned short *)0xffff9202;
                }
-               shifter.syncmode = hw->sync;
+               shifter_st.syncmode = hw->sync;
 
                videl.hht = hw->hht;
                videl.hbb = hw->hbb;
@@ -1952,18 +1952,18 @@ static void stste_get_par(struct atafb_par *par)
 {
        unsigned long addr;
        par->hw.st.mode = shifter_tt.st_shiftmode;
-       par->hw.st.sync = shifter.syncmode;
-       addr = ((shifter.bas_hi & 0xff) << 16) |
-              ((shifter.bas_md & 0xff) << 8);
+       par->hw.st.sync = shifter_st.syncmode;
+       addr = ((shifter_st.bas_hi & 0xff) << 16) |
+              ((shifter_st.bas_md & 0xff) << 8);
        if (ATARIHW_PRESENT(EXTD_SHIFTER))
-               addr |= (shifter.bas_lo & 0xff);
+               addr |= (shifter_st.bas_lo & 0xff);
        par->screen_base = atari_stram_to_virt(addr);
 }
 
 static void stste_set_par(struct atafb_par *par)
 {
        shifter_tt.st_shiftmode = par->hw.st.mode;
-       shifter.syncmode = par->hw.st.sync;
+       shifter_st.syncmode = par->hw.st.sync;
        /* only set screen_base if really necessary */
        if (current_par.screen_base != par->screen_base)
                fbhw->set_screen_base(par->screen_base);
@@ -2018,10 +2018,10 @@ static void stste_set_screen_base(void *s_base)
        unsigned long addr;
        addr = atari_stram_to_phys(s_base);
        /* Setup Screen Memory */
-       shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
-       shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
+       shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+       shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
        if (ATARIHW_PRESENT(EXTD_SHIFTER))
-               shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
+               shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
 }
 
 #endif /* ATAFB_STE */
@@ -2265,9 +2265,9 @@ static void set_screen_base(void *s_base)
 
        addr = atari_stram_to_phys(s_base);
        /* Setup Screen Memory */
-       shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
-       shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
-       shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
+       shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+       shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
+       shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
 }
 
 static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
index c8be1c4..bdc0824 100644 (file)
@@ -566,13 +566,17 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
 
 unmap_release:
        err_idx = i;
-       i = head;
+
+       if (indirect)
+               i = 0;
+       else
+               i = head;
 
        for (n = 0; n < total_sg; n++) {
                if (i == err_idx)
                        break;
                vring_unmap_one_split(vq, &desc[i]);
-               i = virtio16_to_cpu(_vq->vdev, vq->split.vring.desc[i].next);
+               i = virtio16_to_cpu(_vq->vdev, desc[i].next);
        }
 
        if (indirect)
index 4eacfb1..eb729d7 100644 (file)
@@ -168,7 +168,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
                soft_margin = new_margin;
                reload = soft_margin * (mem_fclk_21285 / 256);
                watchdog_ping();
-               /* Fall */
+               /* Fall through */
        case WDIOC_GETTIMEOUT:
                ret = put_user(soft_margin, int_arg);
                break;
index ae1df49..adcabd9 100644 (file)
@@ -386,8 +386,8 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
         */
        trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force);
 
-       map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir,
-                                    attrs);
+       map = swiotlb_tbl_map_single(dev, start_dma_addr, phys,
+                                    size, size, dir, attrs);
        if (map == (phys_addr_t)DMA_MAPPING_ERROR)
                return DMA_MAPPING_ERROR;
 
@@ -397,7 +397,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
         * Ensure that the address returned is DMA'ble
         */
        if (unlikely(!dma_capable(dev, dev_addr, size))) {
-               swiotlb_tbl_unmap_single(dev, map, size, dir,
+               swiotlb_tbl_unmap_single(dev, map, size, size, dir,
                                attrs | DMA_ATTR_SKIP_CPU_SYNC);
                return DMA_MAPPING_ERROR;
        }
@@ -433,7 +433,7 @@ static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 
        /* NOTE: We use dev_addr here, not paddr! */
        if (is_xen_swiotlb_buffer(dev_addr))
-               swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs);
+               swiotlb_tbl_unmap_single(hwdev, paddr, size, size, dir, attrs);
 }
 
 static void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
index a2a8711..fd5133e 100644 (file)
@@ -74,6 +74,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
                        cell = rcu_dereference_raw(net->ws_cell);
                        if (cell) {
                                afs_get_cell(cell);
+                               ret = 0;
                                break;
                        }
                        ret = -EDESTADDRREQ;
@@ -108,6 +109,9 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
 
        done_seqretry(&net->cells_lock, seq);
 
+       if (ret != 0 && cell)
+               afs_put_cell(net, cell);
+
        return ret == 0 ? cell : ERR_PTR(ret);
 }
 
index 4f1b6f4..b86195e 100644 (file)
@@ -505,18 +505,14 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
        struct afs_call *call = container_of(work, struct afs_call, work);
        struct afs_uuid *r = call->request;
 
-       struct {
-               __be32  match;
-       } reply;
-
        _enter("");
 
        if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
-               reply.match = htonl(0);
+               afs_send_empty_reply(call);
        else
-               reply.match = htonl(1);
+               rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
+                                       1, 1, "K-1");
 
-       afs_send_simple_reply(call, &reply, sizeof(reply));
        afs_put_call(call);
        _leave("");
 }
index e640d67..139b4e3 100644 (file)
@@ -440,7 +440,7 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,
  * iterate through the data blob that lists the contents of an AFS directory
  */
 static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
-                          struct key *key)
+                          struct key *key, afs_dataversion_t *_dir_version)
 {
        struct afs_vnode *dvnode = AFS_FS_I(dir);
        struct afs_xdr_dir_page *dbuf;
@@ -460,6 +460,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
        req = afs_read_dir(dvnode, key);
        if (IS_ERR(req))
                return PTR_ERR(req);
+       *_dir_version = req->data_version;
 
        /* round the file position up to the next entry boundary */
        ctx->pos += sizeof(union afs_xdr_dirent) - 1;
@@ -514,7 +515,10 @@ out:
  */
 static int afs_readdir(struct file *file, struct dir_context *ctx)
 {
-       return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file));
+       afs_dataversion_t dir_version;
+
+       return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file),
+                              &dir_version);
 }
 
 /*
@@ -555,7 +559,8 @@ static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
  * - just returns the FID the dentry name maps to if found
  */
 static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
-                            struct afs_fid *fid, struct key *key)
+                            struct afs_fid *fid, struct key *key,
+                            afs_dataversion_t *_dir_version)
 {
        struct afs_super_info *as = dir->i_sb->s_fs_info;
        struct afs_lookup_one_cookie cookie = {
@@ -568,7 +573,7 @@ static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
        _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
 
        /* search the directory */
-       ret = afs_dir_iterate(dir, &cookie.ctx, key);
+       ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version);
        if (ret < 0) {
                _leave(" = %d [iter]", ret);
                return ret;
@@ -642,6 +647,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
        struct afs_server *server;
        struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
        struct inode *inode = NULL, *ti;
+       afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version);
        int ret, i;
 
        _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
@@ -669,12 +675,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
                cookie->fids[i].vid = as->volume->vid;
 
        /* search the directory */
-       ret = afs_dir_iterate(dir, &cookie->ctx, key);
+       ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version);
        if (ret < 0) {
                inode = ERR_PTR(ret);
                goto out;
        }
 
+       dentry->d_fsdata = (void *)(unsigned long)data_version;
+
        inode = ERR_PTR(-ENOENT);
        if (!cookie->found)
                goto out;
@@ -951,7 +959,8 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
                                 inode ? AFS_FS_I(inode) : NULL);
        } else {
                trace_afs_lookup(dvnode, &dentry->d_name,
-                                inode ? AFS_FS_I(inode) : NULL);
+                                IS_ERR_OR_NULL(inode) ? NULL
+                                : AFS_FS_I(inode));
        }
        return d;
 }
@@ -968,7 +977,8 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
        struct dentry *parent;
        struct inode *inode;
        struct key *key;
-       long dir_version, de_version;
+       afs_dataversion_t dir_version;
+       long de_version;
        int ret;
 
        if (flags & LOOKUP_RCU)
@@ -1014,20 +1024,20 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
         * on a 32-bit system, we only have 32 bits in the dentry to store the
         * version.
         */
-       dir_version = (long)dir->status.data_version;
+       dir_version = dir->status.data_version;
        de_version = (long)dentry->d_fsdata;
-       if (de_version == dir_version)
-               goto out_valid;
+       if (de_version == (long)dir_version)
+               goto out_valid_noupdate;
 
-       dir_version = (long)dir->invalid_before;
-       if (de_version - dir_version >= 0)
+       dir_version = dir->invalid_before;
+       if (de_version - (long)dir_version >= 0)
                goto out_valid;
 
        _debug("dir modified");
        afs_stat_v(dir, n_reval);
 
        /* search the directory for this vnode */
-       ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key);
+       ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key, &dir_version);
        switch (ret) {
        case 0:
                /* the filename maps to something */
@@ -1080,7 +1090,8 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
        }
 
 out_valid:
-       dentry->d_fsdata = (void *)dir_version;
+       dentry->d_fsdata = (void *)(unsigned long)dir_version;
+out_valid_noupdate:
        dput(parent);
        key_put(key);
        _leave(" = 1 [valid]");
@@ -1185,6 +1196,20 @@ static void afs_prep_for_new_inode(struct afs_fs_cursor *fc,
        iget_data->cb_s_break = fc->cbi->server->cb_s_break;
 }
 
+/*
+ * Note that a dentry got changed.  We need to set d_fsdata to the data version
+ * number derived from the result of the operation.  It doesn't matter if
+ * d_fsdata goes backwards as we'll just revalidate.
+ */
+static void afs_update_dentry_version(struct afs_fs_cursor *fc,
+                                     struct dentry *dentry,
+                                     struct afs_status_cb *scb)
+{
+       if (fc->ac.error == 0)
+               dentry->d_fsdata =
+                       (void *)(unsigned long)scb->status.data_version;
+}
+
 /*
  * create a directory on an AFS filesystem
  */
@@ -1227,6 +1252,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                afs_check_for_remote_deletion(&fc, dvnode);
                afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
                                        &data_version, &scb[0]);
+               afs_update_dentry_version(&fc, dentry, &scb[0]);
                afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
@@ -1319,6 +1345,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
 
                afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
                                        &data_version, scb);
+               afs_update_dentry_version(&fc, dentry, scb);
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0) {
                        afs_dir_remove_subdir(dentry);
@@ -1458,6 +1485,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
                                        &data_version, &scb[0]);
                afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
                                        &data_version_2, &scb[1]);
+               afs_update_dentry_version(&fc, dentry, &scb[0]);
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
                        ret = afs_dir_remove_link(dvnode, dentry, key);
@@ -1526,6 +1554,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                afs_check_for_remote_deletion(&fc, dvnode);
                afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
                                        &data_version, &scb[0]);
+               afs_update_dentry_version(&fc, dentry, &scb[0]);
                afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
@@ -1607,6 +1636,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
                afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
                                        NULL, &scb[1]);
                ihold(&vnode->vfs_inode);
+               afs_update_dentry_version(&fc, dentry, &scb[0]);
                d_instantiate(dentry, &vnode->vfs_inode);
 
                mutex_unlock(&vnode->io_lock);
@@ -1686,6 +1716,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
                afs_check_for_remote_deletion(&fc, dvnode);
                afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
                                        &data_version, &scb[0]);
+               afs_update_dentry_version(&fc, dentry, &scb[0]);
                afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]);
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
@@ -1791,6 +1822,17 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
+       /* This bit is potentially nasty as there's a potential race with
+        * afs_d_revalidate{,_rcu}().  We have to change d_fsdata on the dentry
+        * to reflect it's new parent's new data_version after the op, but
+        * d_revalidate may see old_dentry between the op having taken place
+        * and the version being updated.
+        *
+        * So drop the old_dentry for now to make other threads go through
+        * lookup instead - which we hold a lock against.
+        */
+       d_drop(old_dentry);
+
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
                afs_dataversion_t orig_data_version;
@@ -1802,9 +1844,9 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (orig_dvnode != new_dvnode) {
                        if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
                                afs_end_vnode_operation(&fc);
-                               goto error_rehash;
+                               goto error_rehash_old;
                        }
-                       new_data_version = new_dvnode->status.data_version;
+                       new_data_version = new_dvnode->status.data_version + 1;
                } else {
                        new_data_version = orig_data_version;
                        new_scb = &scb[0];
@@ -1827,7 +1869,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
                ret = afs_end_vnode_operation(&fc);
                if (ret < 0)
-                       goto error_rehash;
+                       goto error_rehash_old;
        }
 
        if (ret == 0) {
@@ -1853,10 +1895,26 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                drop_nlink(new_inode);
                        spin_unlock(&new_inode->i_lock);
                }
+
+               /* Now we can update d_fsdata on the dentries to reflect their
+                * new parent's data_version.
+                *
+                * Note that if we ever implement RENAME_EXCHANGE, we'll have
+                * to update both dentries with opposing dir versions.
+                */
+               if (new_dvnode != orig_dvnode) {
+                       afs_update_dentry_version(&fc, old_dentry, &scb[1]);
+                       afs_update_dentry_version(&fc, new_dentry, &scb[1]);
+               } else {
+                       afs_update_dentry_version(&fc, old_dentry, &scb[0]);
+                       afs_update_dentry_version(&fc, new_dentry, &scb[0]);
+               }
                d_move(old_dentry, new_dentry);
                goto error_tmp;
        }
 
+error_rehash_old:
+       d_rehash(new_dentry);
 error_rehash:
        if (rehash)
                d_rehash(rehash);
index 56b6957..dd3c55c 100644 (file)
@@ -191,11 +191,13 @@ void afs_put_read(struct afs_read *req)
        int i;
 
        if (refcount_dec_and_test(&req->usage)) {
-               for (i = 0; i < req->nr_pages; i++)
-                       if (req->pages[i])
-                               put_page(req->pages[i]);
-               if (req->pages != req->array)
-                       kfree(req->pages);
+               if (req->pages) {
+                       for (i = 0; i < req->nr_pages; i++)
+                               if (req->pages[i])
+                                       put_page(req->pages[i]);
+                       if (req->pages != req->array)
+                               kfree(req->pages);
+               }
                kfree(req);
        }
 }
index d7e0fd3..cfb0ac4 100644 (file)
@@ -56,23 +56,24 @@ static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
                struct afs_uuid__xdr *xdr;
                struct afs_uuid *uuid;
                int j;
+               int n = entry->nr_servers;
 
                tmp = ntohl(uvldb->serverFlags[i]);
                if (tmp & AFS_VLSF_DONTUSE ||
                    (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
                        continue;
                if (tmp & AFS_VLSF_RWVOL) {
-                       entry->fs_mask[i] |= AFS_VOL_VTM_RW;
+                       entry->fs_mask[n] |= AFS_VOL_VTM_RW;
                        if (vlflags & AFS_VLF_BACKEXISTS)
-                               entry->fs_mask[i] |= AFS_VOL_VTM_BAK;
+                               entry->fs_mask[n] |= AFS_VOL_VTM_BAK;
                }
                if (tmp & AFS_VLSF_ROVOL)
-                       entry->fs_mask[i] |= AFS_VOL_VTM_RO;
-               if (!entry->fs_mask[i])
+                       entry->fs_mask[n] |= AFS_VOL_VTM_RO;
+               if (!entry->fs_mask[n])
                        continue;
 
                xdr = &uvldb->serverNumber[i];
-               uuid = (struct afs_uuid *)&entry->fs_server[i];
+               uuid = (struct afs_uuid *)&entry->fs_server[n];
                uuid->time_low                  = xdr->time_low;
                uuid->time_mid                  = htons(ntohl(xdr->time_mid));
                uuid->time_hi_and_version       = htons(ntohl(xdr->time_hi_and_version));
index 2575503..ca24528 100644 (file)
@@ -2171,7 +2171,7 @@ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl
               key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
        size = round_up(acl->size, 4);
-       call = afs_alloc_flat_call(net, &yfs_RXYFSStoreStatus,
+       call = afs_alloc_flat_call(net, &yfs_RXYFSStoreOpaqueACL2,
                                   sizeof(__be32) * 2 +
                                   sizeof(struct yfs_xdr_YFSFid) +
                                   sizeof(__be32) + size,
index eb657ab..677cb36 100644 (file)
@@ -345,24 +345,15 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
        struct bio *bio;
        bool is_poll = (iocb->ki_flags & IOCB_HIPRI) != 0;
        bool is_read = (iov_iter_rw(iter) == READ), is_sync;
-       bool nowait = (iocb->ki_flags & IOCB_NOWAIT) != 0;
        loff_t pos = iocb->ki_pos;
        blk_qc_t qc = BLK_QC_T_NONE;
-       gfp_t gfp;
-       int ret;
+       int ret = 0;
 
        if ((pos | iov_iter_alignment(iter)) &
            (bdev_logical_block_size(bdev) - 1))
                return -EINVAL;
 
-       if (nowait)
-               gfp = GFP_NOWAIT;
-       else
-               gfp = GFP_KERNEL;
-
-       bio = bio_alloc_bioset(gfp, nr_pages, &blkdev_dio_pool);
-       if (!bio)
-               return -EAGAIN;
+       bio = bio_alloc_bioset(GFP_KERNEL, nr_pages, &blkdev_dio_pool);
 
        dio = container_of(bio, struct blkdev_dio, bio);
        dio->is_sync = is_sync = is_sync_kiocb(iocb);
@@ -384,7 +375,6 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
        if (!is_poll)
                blk_start_plug(&plug);
 
-       ret = 0;
        for (;;) {
                bio_set_dev(bio, bdev);
                bio->bi_iter.bi_sector = pos >> 9;
@@ -409,14 +399,7 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
                        task_io_account_write(bio->bi_iter.bi_size);
                }
 
-               /*
-                * Tell underlying layer to not block for resource shortage.
-                * And if we would have blocked, return error inline instead
-                * of through the bio->bi_end_io() callback.
-                */
-               if (nowait)
-                       bio->bi_opf |= (REQ_NOWAIT | REQ_NOWAIT_INLINE);
-
+               dio->size += bio->bi_iter.bi_size;
                pos += bio->bi_iter.bi_size;
 
                nr_pages = iov_iter_npages(iter, BIO_MAX_PAGES);
@@ -428,13 +411,7 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
                                polled = true;
                        }
 
-                       dio->size += bio->bi_iter.bi_size;
                        qc = submit_bio(bio);
-                       if (qc == BLK_QC_T_EAGAIN) {
-                               dio->size -= bio->bi_iter.bi_size;
-                               ret = -EAGAIN;
-                               goto error;
-                       }
 
                        if (polled)
                                WRITE_ONCE(iocb->ki_cookie, qc);
@@ -455,19 +432,8 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
                        atomic_inc(&dio->ref);
                }
 
-               dio->size += bio->bi_iter.bi_size;
-               qc = submit_bio(bio);
-               if (qc == BLK_QC_T_EAGAIN) {
-                       dio->size -= bio->bi_iter.bi_size;
-                       ret = -EAGAIN;
-                       goto error;
-               }
-
-               bio = bio_alloc(gfp, nr_pages);
-               if (!bio) {
-                       ret = -EAGAIN;
-                       goto error;
-               }
+               submit_bio(bio);
+               bio = bio_alloc(GFP_KERNEL, nr_pages);
        }
 
        if (!is_poll)
@@ -487,7 +453,6 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
        }
        __set_current_state(TASK_RUNNING);
 
-out:
        if (!ret)
                ret = blk_status_to_errno(dio->bio.bi_status);
        if (likely(!ret))
@@ -495,10 +460,6 @@ out:
 
        bio_put(&dio->bio);
        return ret;
-error:
-       if (!is_poll)
-               blk_finish_plug(&plug);
-       goto out;
 }
 
 static ssize_t
index 299e11e..9466006 100644 (file)
@@ -401,7 +401,6 @@ struct btrfs_dev_replace {
 struct raid_kobject {
        u64 flags;
        struct kobject kobj;
-       struct list_head list;
 };
 
 /*
@@ -915,8 +914,6 @@ struct btrfs_fs_info {
        u32 thread_pool_size;
 
        struct kobject *space_info_kobj;
-       struct list_head pending_raid_kobjs;
-       spinlock_t pending_raid_kobjs_lock; /* uncontended */
 
        u64 total_pinned;
 
@@ -2698,7 +2695,6 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr);
 int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           u64 bytes_used, u64 type, u64 chunk_offset,
                           u64 size);
-void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info);
 struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
                                struct btrfs_fs_info *fs_info,
                                const u64 chunk_offset);
index 5f7ee70..97beb35 100644 (file)
@@ -2683,8 +2683,6 @@ int open_ctree(struct super_block *sb,
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
        INIT_LIST_HEAD(&fs_info->delalloc_roots);
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
-       INIT_LIST_HEAD(&fs_info->pending_raid_kobjs);
-       spin_lock_init(&fs_info->pending_raid_kobjs_lock);
        spin_lock_init(&fs_info->delalloc_root_lock);
        spin_lock_init(&fs_info->trans_lock);
        spin_lock_init(&fs_info->fs_roots_radix_lock);
index d3b58e3..8b7eb22 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/sched/mm.h>
 #include <linux/sched/signal.h>
 #include <linux/pagemap.h>
 #include <linux/writeback.h>
@@ -7888,33 +7889,6 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
        return 0;
 }
 
-/* link_block_group will queue up kobjects to add when we're reclaim-safe */
-void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_space_info *space_info;
-       struct raid_kobject *rkobj;
-       LIST_HEAD(list);
-       int ret = 0;
-
-       spin_lock(&fs_info->pending_raid_kobjs_lock);
-       list_splice_init(&fs_info->pending_raid_kobjs, &list);
-       spin_unlock(&fs_info->pending_raid_kobjs_lock);
-
-       list_for_each_entry(rkobj, &list, list) {
-               space_info = btrfs_find_space_info(fs_info, rkobj->flags);
-
-               ret = kobject_add(&rkobj->kobj, &space_info->kobj,
-                               "%s", btrfs_bg_type_to_raid_name(rkobj->flags));
-               if (ret) {
-                       kobject_put(&rkobj->kobj);
-                       break;
-               }
-       }
-       if (ret)
-               btrfs_warn(fs_info,
-                          "failed to add kobject for block cache, ignoring");
-}
-
 static void link_block_group(struct btrfs_block_group_cache *cache)
 {
        struct btrfs_space_info *space_info = cache->space_info;
@@ -7929,18 +7903,36 @@ static void link_block_group(struct btrfs_block_group_cache *cache)
        up_write(&space_info->groups_sem);
 
        if (first) {
-               struct raid_kobject *rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
+               struct raid_kobject *rkobj;
+               unsigned int nofs_flag;
+               int ret;
+
+               /*
+                * Setup a NOFS context because kobject_add(), deep in its call
+                * chain, does GFP_KERNEL allocations, and we are often called
+                * in a context where if reclaim is triggered we can deadlock
+                * (we are either holding a transaction handle or some lock
+                * required for a transaction commit).
+                */
+               nofs_flag = memalloc_nofs_save();
+               rkobj = kzalloc(sizeof(*rkobj), GFP_KERNEL);
                if (!rkobj) {
+                       memalloc_nofs_restore(nofs_flag);
                        btrfs_warn(cache->fs_info,
                                "couldn't alloc memory for raid level kobject");
                        return;
                }
                rkobj->flags = cache->flags;
                kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
-
-               spin_lock(&fs_info->pending_raid_kobjs_lock);
-               list_add_tail(&rkobj->list, &fs_info->pending_raid_kobjs);
-               spin_unlock(&fs_info->pending_raid_kobjs_lock);
+               ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",
+                                 btrfs_bg_type_to_raid_name(rkobj->flags));
+               memalloc_nofs_restore(nofs_flag);
+               if (ret) {
+                       kobject_put(&rkobj->kobj);
+                       btrfs_warn(fs_info,
+                          "failed to add kobject for block cache, ignoring");
+                       return;
+               }
                space_info->block_group_kobjs[index] = &rkobj->kobj;
        }
 }
@@ -8206,7 +8198,6 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
                        inc_block_group_ro(cache, 1);
        }
 
-       btrfs_add_raid_kobjects(info);
        btrfs_init_global_block_rsv(info);
        ret = check_chunk_block_group_mappings(info);
 error:
@@ -8975,6 +8966,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
        struct btrfs_device *device;
        struct list_head *devices;
        u64 group_trimmed;
+       u64 range_end = U64_MAX;
        u64 start;
        u64 end;
        u64 trimmed = 0;
@@ -8984,16 +8976,23 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
        int dev_ret = 0;
        int ret = 0;
 
+       /*
+        * Check range overflow if range->len is set.
+        * The default range->len is U64_MAX.
+        */
+       if (range->len != U64_MAX &&
+           check_add_overflow(range->start, range->len, &range_end))
+               return -EINVAL;
+
        cache = btrfs_lookup_first_block_group(fs_info, range->start);
        for (; cache; cache = next_block_group(cache)) {
-               if (cache->key.objectid >= (range->start + range->len)) {
+               if (cache->key.objectid >= range_end) {
                        btrfs_put_block_group(cache);
                        break;
                }
 
                start = max(range->start, cache->key.objectid);
-               end = min(range->start + range->len,
-                               cache->key.objectid + cache->key.offset);
+               end = min(range_end, cache->key.objectid + cache->key.offset);
 
                if (end - start >= range->minlen) {
                        if (!block_group_cache_done(cache)) {
index 1ff438f..eeb7528 100644 (file)
@@ -3628,6 +3628,13 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
                       TASK_UNINTERRUPTIBLE);
 }
 
+static void end_extent_buffer_writeback(struct extent_buffer *eb)
+{
+       clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
+       smp_mb__after_atomic();
+       wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
+}
+
 /*
  * Lock eb pages and flush the bio if we can't the locks
  *
@@ -3699,8 +3706,11 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
 
                if (!trylock_page(p)) {
                        if (!flush) {
-                               ret = flush_write_bio(epd);
-                               if (ret < 0) {
+                               int err;
+
+                               err = flush_write_bio(epd);
+                               if (err < 0) {
+                                       ret = err;
                                        failed_page_nr = i;
                                        goto err_unlock;
                                }
@@ -3715,16 +3725,23 @@ err_unlock:
        /* Unlock already locked pages */
        for (i = 0; i < failed_page_nr; i++)
                unlock_page(eb->pages[i]);
+       /*
+        * Clear EXTENT_BUFFER_WRITEBACK and wake up anyone waiting on it.
+        * Also set back EXTENT_BUFFER_DIRTY so future attempts to this eb can
+        * be made and undo everything done before.
+        */
+       btrfs_tree_lock(eb);
+       spin_lock(&eb->refs_lock);
+       set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags);
+       end_extent_buffer_writeback(eb);
+       spin_unlock(&eb->refs_lock);
+       percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len,
+                                fs_info->dirty_metadata_batch);
+       btrfs_clear_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+       btrfs_tree_unlock(eb);
        return ret;
 }
 
-static void end_extent_buffer_writeback(struct extent_buffer *eb)
-{
-       clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
-       smp_mb__after_atomic();
-       wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
-}
-
 static void set_btree_ioerr(struct page *page)
 {
        struct extent_buffer *eb = (struct extent_buffer *)page->private;
index 6c8297b..1bfd7e3 100644 (file)
@@ -4985,7 +4985,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                                                      BTRFS_I(inode),
                                                      LOG_OTHER_INODE_ALL,
                                                      0, LLONG_MAX, ctx);
-                                       iput(inode);
+                                       btrfs_add_delayed_iput(inode);
                                }
                        }
                        continue;
@@ -5000,7 +5000,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
                                      LOG_OTHER_INODE, 0, LLONG_MAX, ctx);
                if (ret) {
-                       iput(inode);
+                       btrfs_add_delayed_iput(inode);
                        continue;
                }
 
@@ -5009,7 +5009,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                key.offset = 0;
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0) {
-                       iput(inode);
+                       btrfs_add_delayed_iput(inode);
                        continue;
                }
 
@@ -5056,7 +5056,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
                        }
                        path->slots[0]++;
                }
-               iput(inode);
+               btrfs_add_delayed_iput(inode);
        }
 
        return ret;
@@ -5689,7 +5689,7 @@ process_leaf:
                        }
 
                        if (btrfs_inode_in_log(BTRFS_I(di_inode), trans->transid)) {
-                               iput(di_inode);
+                               btrfs_add_delayed_iput(di_inode);
                                break;
                        }
 
@@ -5701,7 +5701,7 @@ process_leaf:
                        if (!ret &&
                            btrfs_must_commit_transaction(trans, BTRFS_I(di_inode)))
                                ret = 1;
-                       iput(di_inode);
+                       btrfs_add_delayed_iput(di_inode);
                        if (ret)
                                goto next_dir_inode;
                        if (ctx->log_new_dentries) {
@@ -5848,7 +5848,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
                        if (!ret && ctx && ctx->log_new_dentries)
                                ret = log_new_dir_dentries(trans, root,
                                                   BTRFS_I(dir_inode), ctx);
-                       iput(dir_inode);
+                       btrfs_add_delayed_iput(dir_inode);
                        if (ret)
                                goto out;
                }
@@ -5891,7 +5891,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
                        ret = btrfs_log_inode(trans, root, BTRFS_I(inode),
                                              LOG_INODE_EXISTS,
                                              0, LLONG_MAX, ctx);
-               iput(inode);
+               btrfs_add_delayed_iput(inode);
                if (ret)
                        return ret;
 
index d74b74c..a447d3e 100644 (file)
@@ -3087,16 +3087,6 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
        if (ret)
                return ret;
 
-       /*
-        * We add the kobjects here (and after forcing data chunk creation)
-        * since relocation is the only place we'll create chunks of a new
-        * type at runtime.  The only place where we'll remove the last
-        * chunk of a type is the call immediately below this one.  Even
-        * so, we're protected against races with the cleaner thread since
-        * we're covered by the delete_unused_bgs_mutex.
-        */
-       btrfs_add_raid_kobjects(fs_info);
-
        trans = btrfs_start_trans_remove_block_group(root->fs_info,
                                                     chunk_offset);
        if (IS_ERR(trans)) {
@@ -3223,9 +3213,6 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_fs_info *fs_info,
                        btrfs_end_transaction(trans);
                        if (ret < 0)
                                return ret;
-
-                       btrfs_add_raid_kobjects(fs_info);
-
                        return 1;
                }
        }
index e078cc5..b3c8b88 100644 (file)
@@ -913,8 +913,9 @@ get_more_pages:
                        if (page_offset(page) >= ceph_wbc.i_size) {
                                dout("%p page eof %llu\n",
                                     page, ceph_wbc.i_size);
-                               if (ceph_wbc.size_stable ||
-                                   page_offset(page) >= i_size_read(inode))
+                               if ((ceph_wbc.size_stable ||
+                                   page_offset(page) >= i_size_read(inode)) &&
+                                   clear_page_dirty_for_io(page))
                                        mapping->a_ops->invalidatepage(page,
                                                                0, PAGE_SIZE);
                                unlock_page(page);
index d98dcd9..ce0f565 100644 (file)
@@ -1301,6 +1301,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
 {
        struct ceph_inode_info *ci = cap->ci;
        struct inode *inode = &ci->vfs_inode;
+       struct ceph_buffer *old_blob = NULL;
        struct cap_msg_args arg;
        int held, revoking;
        int wake = 0;
@@ -1365,7 +1366,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        ci->i_requested_max_size = arg.max_size;
 
        if (flushing & CEPH_CAP_XATTR_EXCL) {
-               __ceph_build_xattrs_blob(ci);
+               old_blob = __ceph_build_xattrs_blob(ci);
                arg.xattr_version = ci->i_xattrs.version;
                arg.xattr_buf = ci->i_xattrs.blob;
        } else {
@@ -1409,6 +1410,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
 
        spin_unlock(&ci->i_ceph_lock);
 
+       ceph_buffer_put(old_blob);
+
        ret = send_cap_msg(&arg);
        if (ret < 0) {
                dout("error sending cap msg, must requeue %p\n", inode);
index 791f84a..18500ed 100644 (file)
@@ -736,6 +736,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        int issued, new_issued, info_caps;
        struct timespec64 mtime, atime, ctime;
        struct ceph_buffer *xattr_blob = NULL;
+       struct ceph_buffer *old_blob = NULL;
        struct ceph_string *pool_ns = NULL;
        struct ceph_cap *new_cap = NULL;
        int err = 0;
@@ -881,7 +882,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        if ((ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))  &&
            le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) {
                if (ci->i_xattrs.blob)
-                       ceph_buffer_put(ci->i_xattrs.blob);
+                       old_blob = ci->i_xattrs.blob;
                ci->i_xattrs.blob = xattr_blob;
                if (xattr_blob)
                        memcpy(ci->i_xattrs.blob->vec.iov_base,
@@ -1022,8 +1023,8 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
 out:
        if (new_cap)
                ceph_put_cap(mdsc, new_cap);
-       if (xattr_blob)
-               ceph_buffer_put(xattr_blob);
+       ceph_buffer_put(old_blob);
+       ceph_buffer_put(xattr_blob);
        ceph_put_string(pool_ns);
        return err;
 }
index ac9b53b..5083e23 100644 (file)
@@ -111,8 +111,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
                req->r_wait_for_completion = ceph_lock_wait_for_completion;
 
        err = ceph_mdsc_do_request(mdsc, inode, req);
-
-       if (operation == CEPH_MDS_OP_GETFILELOCK) {
+       if (!err && operation == CEPH_MDS_OP_GETFILELOCK) {
                fl->fl_pid = -le64_to_cpu(req->r_reply_info.filelock_reply->pid);
                if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
                        fl->fl_type = F_RDLCK;
index 4c6494e..ccfcc66 100644 (file)
@@ -465,6 +465,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap_snap *capsnap;
        struct ceph_snap_context *old_snapc, *new_snapc;
+       struct ceph_buffer *old_blob = NULL;
        int used, dirty;
 
        capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS);
@@ -541,7 +542,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        capsnap->gid = inode->i_gid;
 
        if (dirty & CEPH_CAP_XATTR_EXCL) {
-               __ceph_build_xattrs_blob(ci);
+               old_blob = __ceph_build_xattrs_blob(ci);
                capsnap->xattr_blob =
                        ceph_buffer_get(ci->i_xattrs.blob);
                capsnap->xattr_version = ci->i_xattrs.version;
@@ -584,6 +585,7 @@ update_snapc:
        }
        spin_unlock(&ci->i_ceph_lock);
 
+       ceph_buffer_put(old_blob);
        kfree(capsnap);
        ceph_put_snap_context(old_snapc);
 }
index d2352fd..6b9f1ee 100644 (file)
@@ -926,7 +926,7 @@ extern int ceph_getattr(const struct path *path, struct kstat *stat,
 int __ceph_setxattr(struct inode *, const char *, const void *, size_t, int);
 ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t);
 extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
-extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
+extern struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci);
 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
 extern const struct xattr_handler *ceph_xattr_handlers[];
 
index 37b458a..939eab7 100644 (file)
@@ -754,12 +754,15 @@ static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
 
 /*
  * If there are dirty xattrs, reencode xattrs into the prealloc_blob
- * and swap into place.
+ * and swap into place.  It returns the old i_xattrs.blob (or NULL) so
+ * that it can be freed by the caller as the i_ceph_lock is likely to be
+ * held.
  */
-void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
+struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci)
 {
        struct rb_node *p;
        struct ceph_inode_xattr *xattr = NULL;
+       struct ceph_buffer *old_blob = NULL;
        void *dest;
 
        dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
@@ -790,12 +793,14 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
                        dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
 
                if (ci->i_xattrs.blob)
-                       ceph_buffer_put(ci->i_xattrs.blob);
+                       old_blob = ci->i_xattrs.blob;
                ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
                ci->i_xattrs.prealloc_blob = NULL;
                ci->i_xattrs.dirty = false;
                ci->i_xattrs.version++;
        }
+
+       return old_blob;
 }
 
 static inline int __get_request_mask(struct inode *in) {
@@ -1036,6 +1041,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_cap_flush *prealloc_cf = NULL;
+       struct ceph_buffer *old_blob = NULL;
        int issued;
        int err;
        int dirty = 0;
@@ -1109,13 +1115,15 @@ retry:
                struct ceph_buffer *blob;
 
                spin_unlock(&ci->i_ceph_lock);
-               dout(" preaallocating new blob size=%d\n", required_blob_size);
+               ceph_buffer_put(old_blob); /* Shouldn't be required */
+               dout(" pre-allocating new blob size=%d\n", required_blob_size);
                blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
                if (!blob)
                        goto do_sync_unlocked;
                spin_lock(&ci->i_ceph_lock);
+               /* prealloc_blob can't be released while holding i_ceph_lock */
                if (ci->i_xattrs.prealloc_blob)
-                       ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+                       old_blob = ci->i_xattrs.prealloc_blob;
                ci->i_xattrs.prealloc_blob = blob;
                goto retry;
        }
@@ -1131,6 +1139,7 @@ retry:
        }
 
        spin_unlock(&ci->i_ceph_lock);
+       ceph_buffer_put(old_blob);
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
        if (dirty)
index 4b21a90..99caf77 100644 (file)
@@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.21"
+#define CIFS_VERSION   "2.22"
 #endif                         /* _CIFSFS_H */
index e232342..592a6ce 100644 (file)
@@ -579,6 +579,7 @@ extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
                                unsigned int *len, unsigned int *offset);
 
 void extract_unc_hostname(const char *unc, const char **h, size_t *len);
+int copy_path_name(char *dst, const char *src);
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
 static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
index e2f9596..3907653 100644 (file)
@@ -942,10 +942,8 @@ PsxDelete:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else { /* BB add path length overrun check */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fileName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, fileName);
        }
 
        params = 6 + name_len;
@@ -1015,10 +1013,8 @@ DelFileRetry:
                                              remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve check for buffer overruns BB */
-               name_len = strnlen(name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->fileName, name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->fileName, name);
        }
        pSMB->SearchAttributes =
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
@@ -1062,10 +1058,8 @@ RmDirRetry:
                                              remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve check for buffer overruns BB */
-               name_len = strnlen(name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->DirName, name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->DirName, name);
        }
 
        pSMB->BufferFormat = 0x04;
@@ -1107,10 +1101,8 @@ MkDirRetry:
                                              remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve check for buffer overruns BB */
-               name_len = strnlen(name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->DirName, name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->DirName, name);
        }
 
        pSMB->BufferFormat = 0x04;
@@ -1157,10 +1149,8 @@ PsxCreat:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, name);
        }
 
        params = 6 + name_len;
@@ -1324,11 +1314,9 @@ OldOpenRetry:
                                      fileName, PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve check for buffer overruns BB */
+       } else {
                count = 0;      /* no pad */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->fileName, fileName, name_len);
+               name_len = copy_path_name(pSMB->fileName, fileName);
        }
        if (*pOplock & REQ_OPLOCK)
                pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
@@ -1442,11 +1430,8 @@ openRetry:
                /* BB improve check for buffer overruns BB */
                /* no pad */
                count = 0;
-               name_len = strnlen(path, PATH_MAX);
-               /* trailing null */
-               name_len++;
+               name_len = copy_path_name(req->fileName, path);
                req->NameLength = cpu_to_le16(name_len);
-               strncpy(req->fileName, path, name_len);
        }
 
        if (*oplock & REQ_OPLOCK)
@@ -2812,15 +2797,10 @@ renameRetry:
                                       remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(from_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->OldFileName, from_name, name_len);
-               name_len2 = strnlen(to_name, PATH_MAX);
-               name_len2++;    /* trailing null */
+       } else {
+               name_len = copy_path_name(pSMB->OldFileName, from_name);
+               name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-               strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
-               name_len2++;    /* trailing null */
                name_len2++;    /* signature byte */
        }
 
@@ -2962,15 +2942,10 @@ copyRetry:
                                       toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fromName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->OldFileName, fromName, name_len);
-               name_len2 = strnlen(toName, PATH_MAX);
-               name_len2++;    /* trailing null */
+       } else {
+               name_len = copy_path_name(pSMB->OldFileName, fromName);
                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-               strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
-               name_len2++;    /* trailing null */
+               name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
                name_len2++;    /* signature byte */
        }
 
@@ -3021,10 +2996,8 @@ createSymLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fromName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fromName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, fromName);
        }
        params = 6 + name_len;
        pSMB->MaxSetupCount = 0;
@@ -3044,10 +3017,8 @@ createSymLinkRetry:
                                        PATH_MAX, nls_codepage, remap);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len_target = strnlen(toName, PATH_MAX);
-               name_len_target++;      /* trailing null */
-               strncpy(data_offset, toName, name_len_target);
+       } else {
+               name_len_target = copy_path_name(data_offset, toName);
        }
 
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -3109,10 +3080,8 @@ createHardLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(toName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, toName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, toName);
        }
        params = 6 + name_len;
        pSMB->MaxSetupCount = 0;
@@ -3131,10 +3100,8 @@ createHardLinkRetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len_target = strnlen(fromName, PATH_MAX);
-               name_len_target++;      /* trailing null */
-               strncpy(data_offset, fromName, name_len_target);
+       } else {
+               name_len_target = copy_path_name(data_offset, fromName);
        }
 
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -3213,15 +3180,10 @@ winCreateHardLinkRetry:
                                       remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(from_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->OldFileName, from_name, name_len);
-               name_len2 = strnlen(to_name, PATH_MAX);
-               name_len2++;    /* trailing null */
+       } else {
+               name_len = copy_path_name(pSMB->OldFileName, from_name);
                pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
-               strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
-               name_len2++;    /* trailing null */
+               name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
                name_len2++;    /* signature byte */
        }
 
@@ -3271,10 +3233,8 @@ querySymLinkRetry:
                                           remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(searchName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, searchName);
        }
 
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
@@ -3691,10 +3651,8 @@ queryAclRetry:
                name_len *= 2;
                pSMB->FileName[name_len] = 0;
                pSMB->FileName[name_len+1] = 0;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(searchName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, searchName);
        }
 
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
@@ -3776,10 +3734,8 @@ setAclRetry:
                                           PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fileName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, fileName);
        }
        params = 6 + name_len;
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -4184,9 +4140,7 @@ QInfRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
        } else {
-               name_len = strnlen(search_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, search_name, name_len);
+               name_len = copy_path_name(pSMB->FileName, search_name);
        }
        pSMB->BufferFormat = 0x04;
        name_len++; /* account for buffer type byte */
@@ -4321,10 +4275,8 @@ QPathInfoRetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(search_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, search_name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, search_name);
        }
 
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
@@ -4490,10 +4442,8 @@ UnixQPathInfoRetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(searchName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, searchName);
        }
 
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
@@ -4593,17 +4543,16 @@ findFirstRetry:
                        pSMB->FileName[name_len+1] = 0;
                        name_len += 2;
                }
-       } else {        /* BB add check for overrun of SMB buf BB */
-               name_len = strnlen(searchName, PATH_MAX);
-/* BB fix here and in unicode clause above ie
-               if (name_len > buffersize-header)
-                       free buffer exit; BB */
-               strncpy(pSMB->FileName, searchName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, searchName);
                if (msearch) {
-                       pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
-                       pSMB->FileName[name_len+1] = '*';
-                       pSMB->FileName[name_len+2] = 0;
-                       name_len += 3;
+                       if (WARN_ON_ONCE(name_len > PATH_MAX-2))
+                               name_len = PATH_MAX-2;
+                       /* overwrite nul byte */
+                       pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
+                       pSMB->FileName[name_len] = '*';
+                       pSMB->FileName[name_len+1] = 0;
+                       name_len += 2;
                }
        }
 
@@ -4898,10 +4847,8 @@ GetInodeNumberRetry:
                                           remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(search_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, search_name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, search_name);
        }
 
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
@@ -5008,9 +4955,7 @@ getDFSRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
        } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(search_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->RequestFileName, search_name, name_len);
+               name_len = copy_path_name(pSMB->RequestFileName, search_name);
        }
 
        if (ses->server->sign)
@@ -5663,10 +5608,8 @@ SetEOFRetry:
                                       PATH_MAX, cifs_sb->local_nls, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(file_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, file_name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, file_name);
        }
        params = 6 + name_len;
        data_count = sizeof(struct file_end_of_file_info);
@@ -5959,10 +5902,8 @@ SetTimesRetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fileName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, fileName);
        }
 
        params = 6 + name_len;
@@ -6040,10 +5981,8 @@ SetAttrLgcyRetry:
                                       PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->fileName, fileName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->fileName, fileName);
        }
        pSMB->attr = cpu_to_le16(dos_attrs);
        pSMB->BufferFormat = 0x04;
@@ -6203,10 +6142,8 @@ setPermsRetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(file_name, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, file_name, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, file_name);
        }
 
        params = 6 + name_len;
@@ -6298,10 +6235,8 @@ QAllEAsRetry:
                                       PATH_MAX, nls_codepage, remap);
                list_len++;     /* trailing null */
                list_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               list_len = strnlen(searchName, PATH_MAX);
-               list_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, list_len);
+       } else {
+               list_len = copy_path_name(pSMB->FileName, searchName);
        }
 
        params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
@@ -6480,10 +6415,8 @@ SetEARetry:
                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fileName, name_len);
+       } else {
+               name_len = copy_path_name(pSMB->FileName, fileName);
        }
 
        params = 6 + name_len;
index a15a6e7..5299eff 100644 (file)
@@ -1113,7 +1113,7 @@ cifs_demultiplex_thread(void *p)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
 
        set_freezable();
-       allow_signal(SIGKILL);
+       allow_kernel_signal(SIGKILL);
        while (server->tcpStatus != CifsExiting) {
                if (try_to_freeze())
                        continue;
@@ -2981,6 +2981,7 @@ static int
 cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
 {
        int rc = 0;
+       int is_domain = 0;
        const char *delim, *payload;
        char *desc;
        ssize_t len;
@@ -3028,6 +3029,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
                        rc = PTR_ERR(key);
                        goto out_err;
                }
+               is_domain = 1;
        }
 
        down_read(&key->sem);
@@ -3085,6 +3087,26 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
                goto out_key_put;
        }
 
+       /*
+        * If we have a domain key then we must set the domainName in the
+        * for the request.
+        */
+       if (is_domain && ses->domainName) {
+               vol->domainname = kstrndup(ses->domainName,
+                                          strlen(ses->domainName),
+                                          GFP_KERNEL);
+               if (!vol->domainname) {
+                       cifs_dbg(FYI, "Unable to allocate %zd bytes for "
+                                "domain\n", len);
+                       rc = -ENOMEM;
+                       kfree(vol->username);
+                       vol->username = NULL;
+                       kzfree(vol->password);
+                       vol->password = NULL;
+                       goto out_key_put;
+               }
+       }
+
 out_key_put:
        up_read(&key->sem);
        key_put(key);
@@ -4209,16 +4231,19 @@ build_unc_path_to_root(const struct smb_vol *vol,
                strlen(vol->prepath) + 1 : 0;
        unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1);
 
+       if (unc_len > MAX_TREE_SIZE)
+               return ERR_PTR(-EINVAL);
+
        full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
-       strncpy(full_path, vol->UNC, unc_len);
+       memcpy(full_path, vol->UNC, unc_len);
        pos = full_path + unc_len;
 
        if (pplen) {
                *pos = CIFS_DIR_SEP(cifs_sb);
-               strncpy(pos + 1, vol->prepath, pplen);
+               memcpy(pos + 1, vol->prepath, pplen);
                pos += pplen;
        }
 
index f26a48d..be424e8 100644 (file)
@@ -69,11 +69,10 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
                return full_path;
 
        if (dfsplen)
-               strncpy(full_path, tcon->treeName, dfsplen);
+               memcpy(full_path, tcon->treeName, dfsplen);
        full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb);
-       strncpy(full_path + dfsplen + 1, vol->prepath, pplen);
+       memcpy(full_path + dfsplen + 1, vol->prepath, pplen);
        convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
-       full_path[dfsplen + pplen] = 0; /* add trailing null */
        return full_path;
 }
 
index f383877..5ad83bd 100644 (file)
@@ -1011,3 +1011,25 @@ void extract_unc_hostname(const char *unc, const char **h, size_t *len)
        *h = unc;
        *len = end - unc;
 }
+
+/**
+ * copy_path_name - copy src path to dst, possibly truncating
+ *
+ * returns number of bytes written (including trailing nul)
+ */
+int copy_path_name(char *dst, const char *src)
+{
+       int name_len;
+
+       /*
+        * PATH_MAX includes nul, so if strlen(src) >= PATH_MAX it
+        * will truncate and strlen(dst) will be PATH_MAX-1
+        */
+       name_len = strscpy(dst, src, PATH_MAX);
+       if (WARN_ON_ONCE(name_len < 0))
+               name_len = PATH_MAX-1;
+
+       /* we count the trailing nul */
+       name_len++;
+       return name_len;
+}
index dcd49ad..4c764ff 100644 (file)
@@ -159,13 +159,16 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
                                 const struct nls_table *nls_cp)
 {
        char *bcc_ptr = *pbcc_area;
+       int len;
 
        /* copy user */
        /* BB what about null user mounts - check that we do this BB */
        /* copy user */
        if (ses->user_name != NULL) {
-               strncpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
-               bcc_ptr += strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
+               len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
+               if (WARN_ON_ONCE(len < 0))
+                       len = CIFS_MAX_USERNAME_LEN - 1;
+               bcc_ptr += len;
        }
        /* else null user mount */
        *bcc_ptr = 0;
@@ -173,8 +176,10 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
 
        /* copy domain */
        if (ses->domainName != NULL) {
-               strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
-               bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+               len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+               if (WARN_ON_ONCE(len < 0))
+                       len = CIFS_MAX_DOMAINNAME_LEN - 1;
+               bcc_ptr += len;
        } /* else we will send a null domain name
             so the server will default to its own domain */
        *bcc_ptr = 0;
@@ -242,9 +247,10 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        kfree(ses->serverOS);
 
-       ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+       ses->serverOS = kmalloc(len + 1, GFP_KERNEL);
        if (ses->serverOS) {
-               strncpy(ses->serverOS, bcc_ptr, len);
+               memcpy(ses->serverOS, bcc_ptr, len);
+               ses->serverOS[len] = 0;
                if (strncmp(ses->serverOS, "OS/2", 4) == 0)
                        cifs_dbg(FYI, "OS/2 server\n");
        }
@@ -258,9 +264,11 @@ static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        kfree(ses->serverNOS);
 
-       ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
-       if (ses->serverNOS)
-               strncpy(ses->serverNOS, bcc_ptr, len);
+       ses->serverNOS = kmalloc(len + 1, GFP_KERNEL);
+       if (ses->serverNOS) {
+               memcpy(ses->serverNOS, bcc_ptr, len);
+               ses->serverNOS[len] = 0;
+       }
 
        bcc_ptr += len + 1;
        bleft -= len + 1;
index f752d83..520f181 100644 (file)
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+struct configfs_fragment {
+       atomic_t frag_count;
+       struct rw_semaphore frag_sem;
+       bool frag_dead;
+};
+
+void put_fragment(struct configfs_fragment *);
+struct configfs_fragment *get_fragment(struct configfs_fragment *);
+
 struct configfs_dirent {
        atomic_t                s_count;
        int                     s_dependent_count;
@@ -34,6 +43,7 @@ struct configfs_dirent {
 #ifdef CONFIG_LOCKDEP
        int                     s_depth;
 #endif
+       struct configfs_fragment *s_frag;
 };
 
 #define CONFIGFS_ROOT          0x0001
@@ -61,8 +71,8 @@ extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct in
 extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
 extern int configfs_create_bin_file(struct config_item *,
                                    const struct configfs_bin_attribute *);
-extern int configfs_make_dirent(struct configfs_dirent *,
-                               struct dentry *, void *, umode_t, int);
+extern int configfs_make_dirent(struct configfs_dirent *, struct dentry *,
+                               void *, umode_t, int, struct configfs_fragment *);
 extern int configfs_dirent_is_ready(struct configfs_dirent *);
 
 extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
@@ -137,6 +147,7 @@ static inline void release_configfs_dirent(struct configfs_dirent * sd)
 {
        if (!(sd->s_type & CONFIGFS_ROOT)) {
                kfree(sd->s_iattr);
+               put_fragment(sd->s_frag);
                kmem_cache_free(configfs_dir_cachep, sd);
        }
 }
index 9211291..79fc25a 100644 (file)
@@ -151,11 +151,38 @@ configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
 
 #endif /* CONFIG_LOCKDEP */
 
+static struct configfs_fragment *new_fragment(void)
+{
+       struct configfs_fragment *p;
+
+       p = kmalloc(sizeof(struct configfs_fragment), GFP_KERNEL);
+       if (p) {
+               atomic_set(&p->frag_count, 1);
+               init_rwsem(&p->frag_sem);
+               p->frag_dead = false;
+       }
+       return p;
+}
+
+void put_fragment(struct configfs_fragment *frag)
+{
+       if (frag && atomic_dec_and_test(&frag->frag_count))
+               kfree(frag);
+}
+
+struct configfs_fragment *get_fragment(struct configfs_fragment *frag)
+{
+       if (likely(frag))
+               atomic_inc(&frag->frag_count);
+       return frag;
+}
+
 /*
  * Allocates a new configfs_dirent and links it to the parent configfs_dirent
  */
 static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd,
-                                                  void *element, int type)
+                                                  void *element, int type,
+                                                  struct configfs_fragment *frag)
 {
        struct configfs_dirent * sd;
 
@@ -175,6 +202,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren
                kmem_cache_free(configfs_dir_cachep, sd);
                return ERR_PTR(-ENOENT);
        }
+       sd->s_frag = get_fragment(frag);
        list_add(&sd->s_sibling, &parent_sd->s_children);
        spin_unlock(&configfs_dirent_lock);
 
@@ -209,11 +237,11 @@ static int configfs_dirent_exists(struct configfs_dirent *parent_sd,
 
 int configfs_make_dirent(struct configfs_dirent * parent_sd,
                         struct dentry * dentry, void * element,
-                        umode_t mode, int type)
+                        umode_t mode, int type, struct configfs_fragment *frag)
 {
        struct configfs_dirent * sd;
 
-       sd = configfs_new_dirent(parent_sd, element, type);
+       sd = configfs_new_dirent(parent_sd, element, type, frag);
        if (IS_ERR(sd))
                return PTR_ERR(sd);
 
@@ -260,7 +288,8 @@ static void init_symlink(struct inode * inode)
  *     until it is validated by configfs_dir_set_ready()
  */
 
-static int configfs_create_dir(struct config_item *item, struct dentry *dentry)
+static int configfs_create_dir(struct config_item *item, struct dentry *dentry,
+                               struct configfs_fragment *frag)
 {
        int error;
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
@@ -273,7 +302,8 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry)
                return error;
 
        error = configfs_make_dirent(p->d_fsdata, dentry, item, mode,
-                                    CONFIGFS_DIR | CONFIGFS_USET_CREATING);
+                                    CONFIGFS_DIR | CONFIGFS_USET_CREATING,
+                                    frag);
        if (unlikely(error))
                return error;
 
@@ -338,9 +368,10 @@ int configfs_create_link(struct configfs_symlink *sl,
 {
        int err = 0;
        umode_t mode = S_IFLNK | S_IRWXUGO;
+       struct configfs_dirent *p = parent->d_fsdata;
 
-       err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode,
-                                  CONFIGFS_ITEM_LINK);
+       err = configfs_make_dirent(p, dentry, sl, mode,
+                                  CONFIGFS_ITEM_LINK, p->s_frag);
        if (!err) {
                err = configfs_create(dentry, mode, init_symlink);
                if (err) {
@@ -599,7 +630,8 @@ static int populate_attrs(struct config_item *item)
 
 static int configfs_attach_group(struct config_item *parent_item,
                                 struct config_item *item,
-                                struct dentry *dentry);
+                                struct dentry *dentry,
+                                struct configfs_fragment *frag);
 static void configfs_detach_group(struct config_item *item);
 
 static void detach_groups(struct config_group *group)
@@ -647,7 +679,8 @@ static void detach_groups(struct config_group *group)
  * try using vfs_mkdir.  Just a thought.
  */
 static int create_default_group(struct config_group *parent_group,
-                               struct config_group *group)
+                               struct config_group *group,
+                               struct configfs_fragment *frag)
 {
        int ret;
        struct configfs_dirent *sd;
@@ -663,7 +696,7 @@ static int create_default_group(struct config_group *parent_group,
                d_add(child, NULL);
 
                ret = configfs_attach_group(&parent_group->cg_item,
-                                           &group->cg_item, child);
+                                           &group->cg_item, child, frag);
                if (!ret) {
                        sd = child->d_fsdata;
                        sd->s_type |= CONFIGFS_USET_DEFAULT;
@@ -677,13 +710,14 @@ static int create_default_group(struct config_group *parent_group,
        return ret;
 }
 
-static int populate_groups(struct config_group *group)
+static int populate_groups(struct config_group *group,
+                          struct configfs_fragment *frag)
 {
        struct config_group *new_group;
        int ret = 0;
 
        list_for_each_entry(new_group, &group->default_groups, group_entry) {
-               ret = create_default_group(group, new_group);
+               ret = create_default_group(group, new_group, frag);
                if (ret) {
                        detach_groups(group);
                        break;
@@ -797,11 +831,12 @@ static void link_group(struct config_group *parent_group, struct config_group *g
  */
 static int configfs_attach_item(struct config_item *parent_item,
                                struct config_item *item,
-                               struct dentry *dentry)
+                               struct dentry *dentry,
+                               struct configfs_fragment *frag)
 {
        int ret;
 
-       ret = configfs_create_dir(item, dentry);
+       ret = configfs_create_dir(item, dentry, frag);
        if (!ret) {
                ret = populate_attrs(item);
                if (ret) {
@@ -831,12 +866,13 @@ static void configfs_detach_item(struct config_item *item)
 
 static int configfs_attach_group(struct config_item *parent_item,
                                 struct config_item *item,
-                                struct dentry *dentry)
+                                struct dentry *dentry,
+                                struct configfs_fragment *frag)
 {
        int ret;
        struct configfs_dirent *sd;
 
-       ret = configfs_attach_item(parent_item, item, dentry);
+       ret = configfs_attach_item(parent_item, item, dentry, frag);
        if (!ret) {
                sd = dentry->d_fsdata;
                sd->s_type |= CONFIGFS_USET_DIR;
@@ -852,7 +888,7 @@ static int configfs_attach_group(struct config_item *parent_item,
                 */
                inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);
                configfs_adjust_dir_dirent_depth_before_populate(sd);
-               ret = populate_groups(to_config_group(item));
+               ret = populate_groups(to_config_group(item), frag);
                if (ret) {
                        configfs_detach_item(item);
                        d_inode(dentry)->i_flags |= S_DEAD;
@@ -1247,6 +1283,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        struct configfs_dirent *sd;
        const struct config_item_type *type;
        struct module *subsys_owner = NULL, *new_item_owner = NULL;
+       struct configfs_fragment *frag;
        char *name;
 
        sd = dentry->d_parent->d_fsdata;
@@ -1265,6 +1302,12 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
                goto out;
        }
 
+       frag = new_fragment();
+       if (!frag) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        /* Get a working ref for the duration of this function */
        parent_item = configfs_get_config_item(dentry->d_parent);
        type = parent_item->ci_type;
@@ -1367,9 +1410,9 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        spin_unlock(&configfs_dirent_lock);
 
        if (group)
-               ret = configfs_attach_group(parent_item, item, dentry);
+               ret = configfs_attach_group(parent_item, item, dentry, frag);
        else
-               ret = configfs_attach_item(parent_item, item, dentry);
+               ret = configfs_attach_item(parent_item, item, dentry, frag);
 
        spin_lock(&configfs_dirent_lock);
        sd->s_type &= ~CONFIGFS_USET_IN_MKDIR;
@@ -1406,6 +1449,7 @@ out_put:
         * reference.
         */
        config_item_put(parent_item);
+       put_fragment(frag);
 
 out:
        return ret;
@@ -1417,6 +1461,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
        struct config_item *item;
        struct configfs_subsystem *subsys;
        struct configfs_dirent *sd;
+       struct configfs_fragment *frag;
        struct module *subsys_owner = NULL, *dead_item_owner = NULL;
        int ret;
 
@@ -1474,6 +1519,16 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
                }
        } while (ret == -EAGAIN);
 
+       frag = sd->s_frag;
+       if (down_write_killable(&frag->frag_sem)) {
+               spin_lock(&configfs_dirent_lock);
+               configfs_detach_rollback(dentry);
+               spin_unlock(&configfs_dirent_lock);
+               return -EINTR;
+       }
+       frag->frag_dead = true;
+       up_write(&frag->frag_sem);
+
        /* Get a working ref for the duration of this function */
        item = configfs_get_config_item(dentry);
 
@@ -1574,7 +1629,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
         */
        err = -ENOENT;
        if (configfs_dirent_is_ready(parent_sd)) {
-               file->private_data = configfs_new_dirent(parent_sd, NULL, 0);
+               file->private_data = configfs_new_dirent(parent_sd, NULL, 0, NULL);
                if (IS_ERR(file->private_data))
                        err = PTR_ERR(file->private_data);
                else
@@ -1732,8 +1787,13 @@ int configfs_register_group(struct config_group *parent_group,
 {
        struct configfs_subsystem *subsys = parent_group->cg_subsys;
        struct dentry *parent;
+       struct configfs_fragment *frag;
        int ret;
 
+       frag = new_fragment();
+       if (!frag)
+               return -ENOMEM;
+
        mutex_lock(&subsys->su_mutex);
        link_group(parent_group, group);
        mutex_unlock(&subsys->su_mutex);
@@ -1741,7 +1801,7 @@ int configfs_register_group(struct config_group *parent_group,
        parent = parent_group->cg_item.ci_dentry;
 
        inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
-       ret = create_default_group(parent_group, group);
+       ret = create_default_group(parent_group, group, frag);
        if (ret)
                goto err_out;
 
@@ -1749,12 +1809,14 @@ int configfs_register_group(struct config_group *parent_group,
        configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
        spin_unlock(&configfs_dirent_lock);
        inode_unlock(d_inode(parent));
+       put_fragment(frag);
        return 0;
 err_out:
        inode_unlock(d_inode(parent));
        mutex_lock(&subsys->su_mutex);
        unlink_group(group);
        mutex_unlock(&subsys->su_mutex);
+       put_fragment(frag);
        return ret;
 }
 EXPORT_SYMBOL(configfs_register_group);
@@ -1770,16 +1832,12 @@ void configfs_unregister_group(struct config_group *group)
        struct configfs_subsystem *subsys = group->cg_subsys;
        struct dentry *dentry = group->cg_item.ci_dentry;
        struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
+       struct configfs_dirent *sd = dentry->d_fsdata;
+       struct configfs_fragment *frag = sd->s_frag;
 
-       mutex_lock(&subsys->su_mutex);
-       if (!group->cg_item.ci_parent->ci_group) {
-               /*
-                * The parent has already been unlinked and detached
-                * due to a rmdir.
-                */
-               goto unlink_group;
-       }
-       mutex_unlock(&subsys->su_mutex);
+       down_write(&frag->frag_sem);
+       frag->frag_dead = true;
+       up_write(&frag->frag_sem);
 
        inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
        spin_lock(&configfs_dirent_lock);
@@ -1796,7 +1854,6 @@ void configfs_unregister_group(struct config_group *group)
        dput(dentry);
 
        mutex_lock(&subsys->su_mutex);
-unlink_group:
        unlink_group(group);
        mutex_unlock(&subsys->su_mutex);
 }
@@ -1853,10 +1910,17 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
        struct dentry *dentry;
        struct dentry *root;
        struct configfs_dirent *sd;
+       struct configfs_fragment *frag;
+
+       frag = new_fragment();
+       if (!frag)
+               return -ENOMEM;
 
        root = configfs_pin_fs();
-       if (IS_ERR(root))
+       if (IS_ERR(root)) {
+               put_fragment(frag);
                return PTR_ERR(root);
+       }
 
        if (!group->cg_item.ci_name)
                group->cg_item.ci_name = group->cg_item.ci_namebuf;
@@ -1872,7 +1936,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                d_add(dentry, NULL);
 
                err = configfs_attach_group(sd->s_element, &group->cg_item,
-                                           dentry);
+                                           dentry, frag);
                if (err) {
                        BUG_ON(d_inode(dentry));
                        d_drop(dentry);
@@ -1890,6 +1954,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                unlink_group(group);
                configfs_release_fs();
        }
+       put_fragment(frag);
 
        return err;
 }
@@ -1899,12 +1964,18 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
        struct config_group *group = &subsys->su_group;
        struct dentry *dentry = group->cg_item.ci_dentry;
        struct dentry *root = dentry->d_sb->s_root;
+       struct configfs_dirent *sd = dentry->d_fsdata;
+       struct configfs_fragment *frag = sd->s_frag;
 
        if (dentry->d_parent != root) {
                pr_err("Tried to unregister non-subsystem!\n");
                return;
        }
 
+       down_write(&frag->frag_sem);
+       frag->frag_dead = true;
+       up_write(&frag->frag_sem);
+
        inode_lock_nested(d_inode(root),
                          I_MUTEX_PARENT);
        inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);
index 61e4db4..fb65b70 100644 (file)
@@ -39,40 +39,44 @@ struct configfs_buffer {
        bool                    write_in_progress;
        char                    *bin_buffer;
        int                     bin_buffer_size;
+       int                     cb_max_size;
+       struct config_item      *item;
+       struct module           *owner;
+       union {
+               struct configfs_attribute       *attr;
+               struct configfs_bin_attribute   *bin_attr;
+       };
 };
 
+static inline struct configfs_fragment *to_frag(struct file *file)
+{
+       struct configfs_dirent *sd = file->f_path.dentry->d_fsdata;
 
-/**
- *     fill_read_buffer - allocate and fill buffer from item.
- *     @dentry:        dentry pointer.
- *     @buffer:        data buffer for file.
- *
- *     Allocate @buffer->page, if it hasn't been already, then call the
- *     config_item's show() method to fill the buffer with this attribute's
- *     data.
- *     This is called only once, on the file's first read.
- */
-static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer)
+       return sd->s_frag;
+}
+
+static int fill_read_buffer(struct file *file, struct configfs_buffer *buffer)
 {
-       struct configfs_attribute * attr = to_attr(dentry);
-       struct config_item * item = to_item(dentry->d_parent);
-       int ret = 0;
-       ssize_t count;
+       struct configfs_fragment *frag = to_frag(file);
+       ssize_t count = -ENOENT;
 
        if (!buffer->page)
                buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
        if (!buffer->page)
                return -ENOMEM;
 
-       count = attr->show(item, buffer->page);
-
-       BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
-       if (count >= 0) {
-               buffer->needs_read_fill = 0;
-               buffer->count = count;
-       } else
-               ret = count;
-       return ret;
+       down_read(&frag->frag_sem);
+       if (!frag->frag_dead)
+               count = buffer->attr->show(buffer->item, buffer->page);
+       up_read(&frag->frag_sem);
+
+       if (count < 0)
+               return count;
+       if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE))
+               return -EIO;
+       buffer->needs_read_fill = 0;
+       buffer->count = count;
+       return 0;
 }
 
 /**
@@ -97,12 +101,13 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
 static ssize_t
 configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-       struct configfs_buffer * buffer = file->private_data;
+       struct configfs_buffer *buffer = file->private_data;
        ssize_t retval = 0;
 
        mutex_lock(&buffer->mutex);
        if (buffer->needs_read_fill) {
-               if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
+               retval = fill_read_buffer(file, buffer);
+               if (retval)
                        goto out;
        }
        pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
@@ -138,10 +143,8 @@ static ssize_t
 configfs_read_bin_file(struct file *file, char __user *buf,
                       size_t count, loff_t *ppos)
 {
+       struct configfs_fragment *frag = to_frag(file);
        struct configfs_buffer *buffer = file->private_data;
-       struct dentry *dentry = file->f_path.dentry;
-       struct config_item *item = to_item(dentry->d_parent);
-       struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
        ssize_t retval = 0;
        ssize_t len = min_t(size_t, count, PAGE_SIZE);
 
@@ -156,14 +159,19 @@ configfs_read_bin_file(struct file *file, char __user *buf,
 
        if (buffer->needs_read_fill) {
                /* perform first read with buf == NULL to get extent */
-               len = bin_attr->read(item, NULL, 0);
+               down_read(&frag->frag_sem);
+               if (!frag->frag_dead)
+                       len = buffer->bin_attr->read(buffer->item, NULL, 0);
+               else
+                       len = -ENOENT;
+               up_read(&frag->frag_sem);
                if (len <= 0) {
                        retval = len;
                        goto out;
                }
 
                /* do not exceed the maximum value */
-               if (bin_attr->cb_max_size && len > bin_attr->cb_max_size) {
+               if (buffer->cb_max_size && len > buffer->cb_max_size) {
                        retval = -EFBIG;
                        goto out;
                }
@@ -176,7 +184,13 @@ configfs_read_bin_file(struct file *file, char __user *buf,
                buffer->bin_buffer_size = len;
 
                /* perform second read to fill buffer */
-               len = bin_attr->read(item, buffer->bin_buffer, len);
+               down_read(&frag->frag_sem);
+               if (!frag->frag_dead)
+                       len = buffer->bin_attr->read(buffer->item,
+                                                    buffer->bin_buffer, len);
+               else
+                       len = -ENOENT;
+               up_read(&frag->frag_sem);
                if (len < 0) {
                        retval = len;
                        vfree(buffer->bin_buffer);
@@ -226,25 +240,17 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
        return error ? -EFAULT : count;
 }
 
-
-/**
- *     flush_write_buffer - push buffer to config_item.
- *     @dentry:        dentry to the attribute
- *     @buffer:        data buffer for file.
- *     @count:         number of bytes
- *
- *     Get the correct pointers for the config_item and the attribute we're
- *     dealing with, then call the store() method for the attribute,
- *     passing the buffer that we acquired in fill_write_buffer().
- */
-
 static int
-flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count)
+flush_write_buffer(struct file *file, struct configfs_buffer *buffer, size_t count)
 {
-       struct configfs_attribute * attr = to_attr(dentry);
-       struct config_item * item = to_item(dentry->d_parent);
-
-       return attr->store(item, buffer->page, count);
+       struct configfs_fragment *frag = to_frag(file);
+       int res = -ENOENT;
+
+       down_read(&frag->frag_sem);
+       if (!frag->frag_dead)
+               res = buffer->attr->store(buffer->item, buffer->page, count);
+       up_read(&frag->frag_sem);
+       return res;
 }
 
 
@@ -268,13 +274,13 @@ flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size
 static ssize_t
 configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
-       struct configfs_buffer * buffer = file->private_data;
+       struct configfs_buffer *buffer = file->private_data;
        ssize_t len;
 
        mutex_lock(&buffer->mutex);
        len = fill_write_buffer(buffer, buf, count);
        if (len > 0)
-               len = flush_write_buffer(file->f_path.dentry, buffer, len);
+               len = flush_write_buffer(file, buffer, len);
        if (len > 0)
                *ppos += len;
        mutex_unlock(&buffer->mutex);
@@ -299,8 +305,6 @@ configfs_write_bin_file(struct file *file, const char __user *buf,
                        size_t count, loff_t *ppos)
 {
        struct configfs_buffer *buffer = file->private_data;
-       struct dentry *dentry = file->f_path.dentry;
-       struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
        void *tbuf = NULL;
        ssize_t len;
 
@@ -316,8 +320,8 @@ configfs_write_bin_file(struct file *file, const char __user *buf,
        /* buffer grows? */
        if (*ppos + count > buffer->bin_buffer_size) {
 
-               if (bin_attr->cb_max_size &&
-                       *ppos + count > bin_attr->cb_max_size) {
+               if (buffer->cb_max_size &&
+                       *ppos + count > buffer->cb_max_size) {
                        len = -EFBIG;
                        goto out;
                }
@@ -349,31 +353,51 @@ out:
        return len;
 }
 
-static int check_perm(struct inode * inode, struct file * file, int type)
+static int __configfs_open_file(struct inode *inode, struct file *file, int type)
 {
-       struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
-       struct configfs_attribute * attr = to_attr(file->f_path.dentry);
-       struct configfs_bin_attribute *bin_attr = NULL;
-       struct configfs_buffer * buffer;
-       struct configfs_item_operations * ops = NULL;
-       int error = 0;
+       struct dentry *dentry = file->f_path.dentry;
+       struct configfs_fragment *frag = to_frag(file);
+       struct configfs_attribute *attr;
+       struct configfs_buffer *buffer;
+       int error;
 
-       if (!item || !attr)
-               goto Einval;
+       error = -ENOMEM;
+       buffer = kzalloc(sizeof(struct configfs_buffer), GFP_KERNEL);
+       if (!buffer)
+               goto out;
 
-       if (type & CONFIGFS_ITEM_BIN_ATTR)
-               bin_attr = to_bin_attr(file->f_path.dentry);
+       error = -ENOENT;
+       down_read(&frag->frag_sem);
+       if (unlikely(frag->frag_dead))
+               goto out_free_buffer;
 
-       /* Grab the module reference for this attribute if we have one */
-       if (!try_module_get(attr->ca_owner)) {
-               error = -ENODEV;
-               goto Done;
+       error = -EINVAL;
+       buffer->item = to_item(dentry->d_parent);
+       if (!buffer->item)
+               goto out_free_buffer;
+
+       attr = to_attr(dentry);
+       if (!attr)
+               goto out_put_item;
+
+       if (type & CONFIGFS_ITEM_BIN_ATTR) {
+               buffer->bin_attr = to_bin_attr(dentry);
+               buffer->cb_max_size = buffer->bin_attr->cb_max_size;
+       } else {
+               buffer->attr = attr;
        }
 
-       if (item->ci_type)
-               ops = item->ci_type->ct_item_ops;
-       else
-               goto Eaccess;
+       buffer->owner = attr->ca_owner;
+       /* Grab the module reference for this attribute if we have one */
+       error = -ENODEV;
+       if (!try_module_get(buffer->owner))
+               goto out_put_item;
+
+       error = -EACCES;
+       if (!buffer->item->ci_type)
+               goto out_put_module;
+
+       buffer->ops = buffer->item->ci_type->ct_item_ops;
 
        /* File needs write support.
         * The inode's perms must say it's ok,
@@ -381,13 +405,11 @@ static int check_perm(struct inode * inode, struct file * file, int type)
         */
        if (file->f_mode & FMODE_WRITE) {
                if (!(inode->i_mode & S_IWUGO))
-                       goto Eaccess;
-
+                       goto out_put_module;
                if ((type & CONFIGFS_ITEM_ATTR) && !attr->store)
-                       goto Eaccess;
-
-               if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->write)
-                       goto Eaccess;
+                       goto out_put_module;
+               if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->write)
+                       goto out_put_module;
        }
 
        /* File needs read support.
@@ -396,92 +418,72 @@ static int check_perm(struct inode * inode, struct file * file, int type)
         */
        if (file->f_mode & FMODE_READ) {
                if (!(inode->i_mode & S_IRUGO))
-                       goto Eaccess;
-
+                       goto out_put_module;
                if ((type & CONFIGFS_ITEM_ATTR) && !attr->show)
-                       goto Eaccess;
-
-               if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->read)
-                       goto Eaccess;
+                       goto out_put_module;
+               if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->read)
+                       goto out_put_module;
        }
 
-       /* No error? Great, allocate a buffer for the file, and store it
-        * it in file->private_data for easy access.
-        */
-       buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
-       if (!buffer) {
-               error = -ENOMEM;
-               goto Enomem;
-       }
        mutex_init(&buffer->mutex);
        buffer->needs_read_fill = 1;
        buffer->read_in_progress = false;
        buffer->write_in_progress = false;
-       buffer->ops = ops;
        file->private_data = buffer;
-       goto Done;
+       up_read(&frag->frag_sem);
+       return 0;
 
- Einval:
-       error = -EINVAL;
-       goto Done;
- Eaccess:
-       error = -EACCES;
- Enomem:
-       module_put(attr->ca_owner);
- Done:
-       if (error && item)
-               config_item_put(item);
+out_put_module:
+       module_put(buffer->owner);
+out_put_item:
+       config_item_put(buffer->item);
+out_free_buffer:
+       up_read(&frag->frag_sem);
+       kfree(buffer);
+out:
        return error;
 }
 
 static int configfs_release(struct inode *inode, struct file *filp)
 {
-       struct config_item * item = to_item(filp->f_path.dentry->d_parent);
-       struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
-       struct module * owner = attr->ca_owner;
-       struct configfs_buffer * buffer = filp->private_data;
-
-       if (item)
-               config_item_put(item);
-       /* After this point, attr should not be accessed. */
-       module_put(owner);
-
-       if (buffer) {
-               if (buffer->page)
-                       free_page((unsigned long)buffer->page);
-               mutex_destroy(&buffer->mutex);
-               kfree(buffer);
-       }
+       struct configfs_buffer *buffer = filp->private_data;
+
+       module_put(buffer->owner);
+       if (buffer->page)
+               free_page((unsigned long)buffer->page);
+       mutex_destroy(&buffer->mutex);
+       kfree(buffer);
        return 0;
 }
 
 static int configfs_open_file(struct inode *inode, struct file *filp)
 {
-       return check_perm(inode, filp, CONFIGFS_ITEM_ATTR);
+       return __configfs_open_file(inode, filp, CONFIGFS_ITEM_ATTR);
 }
 
 static int configfs_open_bin_file(struct inode *inode, struct file *filp)
 {
-       return check_perm(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
+       return __configfs_open_file(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
 }
 
-static int configfs_release_bin_file(struct inode *inode, struct file *filp)
+static int configfs_release_bin_file(struct inode *inode, struct file *file)
 {
-       struct configfs_buffer *buffer = filp->private_data;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct config_item *item = to_item(dentry->d_parent);
-       struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry);
-       ssize_t len = 0;
-       int ret;
+       struct configfs_buffer *buffer = file->private_data;
 
        buffer->read_in_progress = false;
 
        if (buffer->write_in_progress) {
+               struct configfs_fragment *frag = to_frag(file);
                buffer->write_in_progress = false;
 
-               len = bin_attr->write(item, buffer->bin_buffer,
-                               buffer->bin_buffer_size);
-
+               down_read(&frag->frag_sem);
+               if (!frag->frag_dead) {
+                       /* result of ->release() is ignored */
+                       buffer->bin_attr->write(buffer->item,
+                                       buffer->bin_buffer,
+                                       buffer->bin_buffer_size);
+               }
+               up_read(&frag->frag_sem);
                /* vfree on NULL is safe */
                vfree(buffer->bin_buffer);
                buffer->bin_buffer = NULL;
@@ -489,10 +491,8 @@ static int configfs_release_bin_file(struct inode *inode, struct file *filp)
                buffer->needs_read_fill = 1;
        }
 
-       ret = configfs_release(inode, filp);
-       if (len < 0)
-               return len;
-       return ret;
+       configfs_release(inode, file);
+       return 0;
 }
 
 
@@ -527,7 +527,7 @@ int configfs_create_file(struct config_item * item, const struct configfs_attrib
 
        inode_lock_nested(d_inode(dir), I_MUTEX_NORMAL);
        error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode,
-                                    CONFIGFS_ITEM_ATTR);
+                                    CONFIGFS_ITEM_ATTR, parent_sd->s_frag);
        inode_unlock(d_inode(dir));
 
        return error;
@@ -549,7 +549,7 @@ int configfs_create_bin_file(struct config_item *item,
 
        inode_lock_nested(dir->d_inode, I_MUTEX_NORMAL);
        error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode,
-                                    CONFIGFS_ITEM_BIN_ATTR);
+                                    CONFIGFS_ITEM_BIN_ATTR, parent_sd->s_frag);
        inode_unlock(dir->d_inode);
 
        return error;
index 420fe3d..006b7a2 100644 (file)
@@ -4586,7 +4586,6 @@ static int __ext4_get_inode_loc(struct inode *inode,
        struct buffer_head      *bh;
        struct super_block      *sb = inode->i_sb;
        ext4_fsblk_t            block;
-       struct blk_plug         plug;
        int                     inodes_per_block, inode_offset;
 
        iloc->bh = NULL;
@@ -4675,7 +4674,6 @@ make_io:
                 * If we need to do any I/O, try to pre-readahead extra
                 * blocks from the inode table.
                 */
-               blk_start_plug(&plug);
                if (EXT4_SB(sb)->s_inode_readahead_blks) {
                        ext4_fsblk_t b, end, table;
                        unsigned num;
@@ -4706,7 +4704,6 @@ make_io:
                get_bh(bh);
                bh->b_end_io = end_buffer_read_sync;
                submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh);
-               blk_finish_plug(&plug);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        EXT4_ERROR_INODE_BLOCK(inode, block,
index d542f1c..cfb48bd 100644 (file)
@@ -679,6 +679,13 @@ static void io_put_req(struct io_kiocb *req)
                io_free_req(req);
 }
 
+static unsigned io_cqring_events(struct io_cq_ring *ring)
+{
+       /* See comment at the top of this file */
+       smp_rmb();
+       return READ_ONCE(ring->r.tail) - READ_ONCE(ring->r.head);
+}
+
 /*
  * Find and free completed poll iocbs
  */
@@ -771,7 +778,7 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
 static int io_iopoll_getevents(struct io_ring_ctx *ctx, unsigned int *nr_events,
                                long min)
 {
-       while (!list_empty(&ctx->poll_list)) {
+       while (!list_empty(&ctx->poll_list) && !need_resched()) {
                int ret;
 
                ret = io_do_iopoll(ctx, nr_events, min);
@@ -798,6 +805,12 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
                unsigned int nr_events = 0;
 
                io_iopoll_getevents(ctx, &nr_events, 1);
+
+               /*
+                * Ensure we allow local-to-the-cpu processing to take place,
+                * in this case we need to ensure that we reap all events.
+                */
+               cond_resched();
        }
        mutex_unlock(&ctx->uring_lock);
 }
@@ -805,11 +818,42 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
 static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
                           long min)
 {
-       int ret = 0;
+       int iters, ret = 0;
 
+       /*
+        * We disallow the app entering submit/complete with polling, but we
+        * still need to lock the ring to prevent racing with polled issue
+        * that got punted to a workqueue.
+        */
+       mutex_lock(&ctx->uring_lock);
+
+       iters = 0;
        do {
                int tmin = 0;
 
+               /*
+                * Don't enter poll loop if we already have events pending.
+                * If we do, we can potentially be spinning for commands that
+                * already triggered a CQE (eg in error).
+                */
+               if (io_cqring_events(ctx->cq_ring))
+                       break;
+
+               /*
+                * If a submit got punted to a workqueue, we can have the
+                * application entering polling for a command before it gets
+                * issued. That app will hold the uring_lock for the duration
+                * of the poll right here, so we need to take a breather every
+                * now and then to ensure that the issue has a chance to add
+                * the poll to the issued list. Otherwise we can spin here
+                * forever, while the workqueue is stuck trying to acquire the
+                * very same mutex.
+                */
+               if (!(++iters & 7)) {
+                       mutex_unlock(&ctx->uring_lock);
+                       mutex_lock(&ctx->uring_lock);
+               }
+
                if (*nr_events < min)
                        tmin = min - *nr_events;
 
@@ -819,6 +863,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
                ret = 0;
        } while (min && !*nr_events && !need_resched());
 
+       mutex_unlock(&ctx->uring_lock);
        return ret;
 }
 
@@ -1097,10 +1142,8 @@ static int io_import_fixed(struct io_ring_ctx *ctx, int rw,
 
                        iter->bvec = bvec + seg_skip;
                        iter->nr_segs -= seg_skip;
-                       iter->count -= (seg_skip << PAGE_SHIFT);
+                       iter->count -= bvec->bv_len + offset;
                        iter->iov_offset = offset & ~PAGE_MASK;
-                       if (iter->iov_offset)
-                               iter->count -= iter->iov_offset;
                }
        }
 
@@ -2025,6 +2068,15 @@ static int io_queue_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
 {
        int ret;
 
+       ret = io_req_defer(ctx, req, s->sqe);
+       if (ret) {
+               if (ret != -EIOCBQUEUED) {
+                       io_free_req(req);
+                       io_cqring_add_event(ctx, s->sqe->user_data, ret);
+               }
+               return 0;
+       }
+
        ret = __io_submit_sqe(ctx, req, s, true);
        if (ret == -EAGAIN && !(req->flags & REQ_F_NOWAIT)) {
                struct io_uring_sqe *sqe_copy;
@@ -2097,13 +2149,6 @@ err:
                return;
        }
 
-       ret = io_req_defer(ctx, req, s->sqe);
-       if (ret) {
-               if (ret != -EIOCBQUEUED)
-                       goto err_req;
-               return;
-       }
-
        /*
         * If we already have a head request, queue this one for async
         * submittal once the head completes. If we don't have a head but
@@ -2280,15 +2325,7 @@ static int io_sq_thread(void *data)
                        unsigned nr_events = 0;
 
                        if (ctx->flags & IORING_SETUP_IOPOLL) {
-                               /*
-                                * We disallow the app entering submit/complete
-                                * with polling, but we still need to lock the
-                                * ring to prevent racing with polled issue
-                                * that got punted to a workqueue.
-                                */
-                               mutex_lock(&ctx->uring_lock);
                                io_iopoll_check(ctx, &nr_events, 0);
-                               mutex_unlock(&ctx->uring_lock);
                        } else {
                                /*
                                 * Normal IO, just pretend everything completed.
@@ -2433,13 +2470,6 @@ static int io_ring_submit(struct io_ring_ctx *ctx, unsigned int to_submit)
        return submit;
 }
 
-static unsigned io_cqring_events(struct io_cq_ring *ring)
-{
-       /* See comment at the top of this file */
-       smp_rmb();
-       return READ_ONCE(ring->r.tail) - READ_ONCE(ring->r.head);
-}
-
 /*
  * Wait until events become available, if we don't already have some. The
  * application must reap them itself, as they reside on the shared cq ring.
@@ -3190,9 +3220,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
                min_complete = min(min_complete, ctx->cq_entries);
 
                if (ctx->flags & IORING_SETUP_IOPOLL) {
-                       mutex_lock(&ctx->uring_lock);
                        ret = io_iopoll_check(ctx, &nr_events, min_complete);
-                       mutex_unlock(&ctx->uring_lock);
                } else {
                        ret = io_cqring_wait(ctx, min_complete, sig, sigsz);
                }
index 8d50109..0adfd88 100644 (file)
@@ -1487,7 +1487,7 @@ static int nfs_finish_open(struct nfs_open_context *ctx,
        if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
                nfs_file_set_open_context(file, ctx);
        else
-               err = -ESTALE;
+               err = -EOPENSTALE;
 out:
        return err;
 }
index 0cb4424..222d711 100644 (file)
@@ -401,15 +401,21 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
        unsigned long bytes = 0;
        struct nfs_direct_req *dreq = hdr->dreq;
 
-       if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
-               goto out_put;
-
        spin_lock(&dreq->lock);
-       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0))
+       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
                dreq->error = hdr->error;
-       else
+
+       if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+               spin_unlock(&dreq->lock);
+               goto out_put;
+       }
+
+       if (hdr->good_bytes != 0)
                nfs_direct_good_bytes(dreq, hdr);
 
+       if (test_bit(NFS_IOHDR_EOF, &hdr->flags))
+               dreq->error = 0;
+
        spin_unlock(&dreq->lock);
 
        while (!list_empty(&hdr->pages)) {
@@ -782,16 +788,19 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
        bool request_commit = false;
        struct nfs_page *req = nfs_list_entry(hdr->pages.next);
 
-       if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
-               goto out_put;
-
        nfs_init_cinfo_from_dreq(&cinfo, dreq);
 
        spin_lock(&dreq->lock);
 
        if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
                dreq->error = hdr->error;
-       if (dreq->error == 0) {
+
+       if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+               spin_unlock(&dreq->lock);
+               goto out_put;
+       }
+
+       if (hdr->good_bytes != 0) {
                nfs_direct_good_bytes(dreq, hdr);
                if (nfs_write_need_commit(hdr)) {
                        if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
index b04e20d..5657b7f 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/nfs_page.h>
 #include <linux/module.h>
 #include <linux/sched/mm.h>
@@ -928,7 +929,9 @@ retry:
        pgm = &pgio->pg_mirrors[0];
        pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
 
-       pgio->pg_maxretrans = io_maxretrans;
+       if (NFS_SERVER(pgio->pg_inode)->flags &
+                       (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
+               pgio->pg_maxretrans = io_maxretrans;
        return;
 out_nolseg:
        if (pgio->pg_error < 0)
@@ -940,6 +943,7 @@ out_mds:
                        pgio->pg_lseg);
        pnfs_put_lseg(pgio->pg_lseg);
        pgio->pg_lseg = NULL;
+       pgio->pg_maxretrans = 0;
        nfs_pageio_reset_read_mds(pgio);
 }
 
@@ -1000,7 +1004,9 @@ retry:
                pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
        }
 
-       pgio->pg_maxretrans = io_maxretrans;
+       if (NFS_SERVER(pgio->pg_inode)->flags &
+                       (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR))
+               pgio->pg_maxretrans = io_maxretrans;
        return;
 
 out_mds:
@@ -1010,6 +1016,7 @@ out_mds:
                        pgio->pg_lseg);
        pnfs_put_lseg(pgio->pg_lseg);
        pgio->pg_lseg = NULL;
+       pgio->pg_maxretrans = 0;
        nfs_pageio_reset_write_mds(pgio);
 }
 
@@ -1148,8 +1155,6 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
                break;
        case -NFS4ERR_RETRY_UNCACHED_REP:
                break;
-       case -EAGAIN:
-               return -NFS4ERR_RESET_TO_PNFS;
        /* Invalidate Layout errors */
        case -NFS4ERR_PNFS_NO_LAYOUT:
        case -ESTALE:           /* mapped NFS4ERR_STALE */
@@ -1210,7 +1215,6 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
        case -EBADHANDLE:
        case -ELOOP:
        case -ENOSPC:
-       case -EAGAIN:
                break;
        case -EJUKEBOX:
                nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
@@ -1445,16 +1449,6 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data)
        ff_layout_read_prepare_common(task, hdr);
 }
 
-static void
-ff_layout_io_prepare_transmit(struct rpc_task *task,
-               void *data)
-{
-       struct nfs_pgio_header *hdr = data;
-
-       if (!pnfs_is_valid_lseg(hdr->lseg))
-               rpc_exit(task, -EAGAIN);
-}
-
 static void ff_layout_read_call_done(struct rpc_task *task, void *data)
 {
        struct nfs_pgio_header *hdr = data;
@@ -1740,7 +1734,6 @@ static void ff_layout_commit_release(void *data)
 
 static const struct rpc_call_ops ff_layout_read_call_ops_v3 = {
        .rpc_call_prepare = ff_layout_read_prepare_v3,
-       .rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
        .rpc_call_done = ff_layout_read_call_done,
        .rpc_count_stats = ff_layout_read_count_stats,
        .rpc_release = ff_layout_read_release,
@@ -1748,7 +1741,6 @@ static const struct rpc_call_ops ff_layout_read_call_ops_v3 = {
 
 static const struct rpc_call_ops ff_layout_read_call_ops_v4 = {
        .rpc_call_prepare = ff_layout_read_prepare_v4,
-       .rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
        .rpc_call_done = ff_layout_read_call_done,
        .rpc_count_stats = ff_layout_read_count_stats,
        .rpc_release = ff_layout_read_release,
@@ -1756,7 +1748,6 @@ static const struct rpc_call_ops ff_layout_read_call_ops_v4 = {
 
 static const struct rpc_call_ops ff_layout_write_call_ops_v3 = {
        .rpc_call_prepare = ff_layout_write_prepare_v3,
-       .rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
        .rpc_call_done = ff_layout_write_call_done,
        .rpc_count_stats = ff_layout_write_count_stats,
        .rpc_release = ff_layout_write_release,
@@ -1764,7 +1755,6 @@ static const struct rpc_call_ops ff_layout_write_call_ops_v3 = {
 
 static const struct rpc_call_ops ff_layout_write_call_ops_v4 = {
        .rpc_call_prepare = ff_layout_write_prepare_v4,
-       .rpc_call_prepare_transmit = ff_layout_io_prepare_transmit,
        .rpc_call_done = ff_layout_write_call_done,
        .rpc_count_stats = ff_layout_write_count_stats,
        .rpc_release = ff_layout_write_release,
index 8a17582..2a03bfe 100644 (file)
@@ -1403,12 +1403,22 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
                return 0;
 
+       if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
+               /* Only a mounted-on-fileid? Just exit */
+               if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
+                       return 0;
        /* Has the inode gone and changed behind our back? */
-       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
+       } else if (nfsi->fileid != fattr->fileid) {
+               /* Is this perhaps the mounted-on fileid? */
+               if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
+                   nfsi->fileid == fattr->mounted_on_fileid)
+                       return 0;
                return -ESTALE;
+       }
        if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                return -ESTALE;
 
+
        if (!nfs_file_has_buffered_writers(nfsi)) {
                /* Verify a few of the more important attributes */
                if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr))
@@ -1768,18 +1778,6 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
 EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
 
 
-static inline bool nfs_fileid_valid(struct nfs_inode *nfsi,
-                                   struct nfs_fattr *fattr)
-{
-       bool ret1 = true, ret2 = true;
-
-       if (fattr->valid & NFS_ATTR_FATTR_FILEID)
-               ret1 = (nfsi->fileid == fattr->fileid);
-       if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
-               ret2 = (nfsi->fileid == fattr->mounted_on_fileid);
-       return ret1 || ret2;
-}
-
 /*
  * Many nfs protocol calls return the new file attributes after
  * an operation.  Here we update the inode to reflect the state
@@ -1810,7 +1808,16 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        nfs_display_fhandle_hash(NFS_FH(inode)),
                        atomic_read(&inode->i_count), fattr->valid);
 
-       if (!nfs_fileid_valid(nfsi, fattr)) {
+       if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
+               /* Only a mounted-on-fileid? Just exit */
+               if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
+                       return 0;
+       /* Has the inode gone and changed behind our back? */
+       } else if (nfsi->fileid != fattr->fileid) {
+               /* Is this perhaps the mounted-on fileid? */
+               if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
+                   nfsi->fileid == fattr->mounted_on_fileid)
+                       return 0;
                printk(KERN_ERR "NFS: server %s error: fileid changed\n"
                        "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
                        NFS_SERVER(inode)->nfs_client->cl_hostname,
index a2346a2..e64f810 100644 (file)
@@ -775,3 +775,13 @@ static inline bool nfs_error_is_fatal(int err)
        }
 }
 
+static inline bool nfs_error_is_fatal_on_server(int err)
+{
+       switch (err) {
+       case 0:
+       case -ERESTARTSYS:
+       case -EINTR:
+               return false;
+       }
+       return nfs_error_is_fatal(err);
+}
index 96db471..339663d 100644 (file)
@@ -73,13 +73,13 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                switch (err) {
-               case -EPERM:
-               case -EACCES:
-               case -EDQUOT:
-               case -ENOSPC:
-               case -EROFS:
-                       goto out_put_ctx;
                default:
+                       goto out_put_ctx;
+               case -ENOENT:
+               case -ESTALE:
+               case -EISDIR:
+               case -ENOTDIR:
+               case -ELOOP:
                        goto out_drop;
                }
        }
index ed4e1b0..20b3717 100644 (file)
@@ -590,7 +590,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
        }
 
        hdr->res.fattr   = &hdr->fattr;
-       hdr->res.count   = count;
+       hdr->res.count   = 0;
        hdr->res.eof     = 0;
        hdr->res.verf    = &hdr->verf;
        nfs_fattr_init(&hdr->fattr);
@@ -1251,20 +1251,23 @@ static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc,
 int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
                      struct nfs_pgio_header *hdr)
 {
-       LIST_HEAD(failed);
+       LIST_HEAD(pages);
 
        desc->pg_io_completion = hdr->io_completion;
        desc->pg_dreq = hdr->dreq;
-       while (!list_empty(&hdr->pages)) {
-               struct nfs_page *req = nfs_list_entry(hdr->pages.next);
+       list_splice_init(&hdr->pages, &pages);
+       while (!list_empty(&pages)) {
+               struct nfs_page *req = nfs_list_entry(pages.next);
 
                if (!nfs_pageio_add_request(desc, req))
-                       nfs_list_move_request(req, &failed);
+                       break;
        }
        nfs_pageio_complete(desc);
-       if (!list_empty(&failed)) {
-               list_move(&failed, &hdr->pages);
-               return desc->pg_error < 0 ? desc->pg_error : -EIO;
+       if (!list_empty(&pages)) {
+               int err = desc->pg_error < 0 ? desc->pg_error : -EIO;
+               hdr->completion_ops->error_cleanup(&pages, err);
+               nfs_set_pgio_error(hdr, err, hdr->io_start);
+               return err;
        }
        return 0;
 }
index c0046c3..82af480 100644 (file)
@@ -627,11 +627,16 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
                        /* Add this address as an alias */
                        rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
                                        rpc_clnt_test_and_add_xprt, NULL);
-               } else
-                       clp = get_v3_ds_connect(mds_srv,
-                                       (struct sockaddr *)&da->da_addr,
-                                       da->da_addrlen, IPPROTO_TCP,
-                                       timeo, retrans);
+                       continue;
+               }
+               clp = get_v3_ds_connect(mds_srv,
+                               (struct sockaddr *)&da->da_addr,
+                               da->da_addrlen, IPPROTO_TCP,
+                               timeo, retrans);
+               if (IS_ERR(clp))
+                       continue;
+               clp->cl_rpcclient->cl_softerr = 0;
+               clp->cl_rpcclient->cl_softrtry = 0;
        }
 
        if (IS_ERR(clp)) {
index 5552fa8..0f7288b 100644 (file)
@@ -594,7 +594,8 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
                /* Emulate the eof flag, which isn't normally needed in NFSv2
                 * as it is guaranteed to always return the file attributes
                 */
-               if (hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
+               if ((hdr->res.count == 0 && hdr->args.count > 0) ||
+                   hdr->args.offset + hdr->res.count >= hdr->res.fattr->size)
                        hdr->res.eof = 1;
        }
        return 0;
@@ -615,8 +616,10 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task,
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
 {
-       if (task->tk_status >= 0)
+       if (task->tk_status >= 0) {
+               hdr->res.count = hdr->args.count;
                nfs_writeback_update_inode(hdr);
+       }
        return 0;
 }
 
index c19841c..cfe0b58 100644 (file)
@@ -91,19 +91,25 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
 
-static void nfs_readpage_release(struct nfs_page *req)
+static void nfs_readpage_release(struct nfs_page *req, int error)
 {
        struct inode *inode = d_inode(nfs_req_openctx(req)->dentry);
+       struct page *page = req->wb_page;
 
        dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id,
                (unsigned long long)NFS_FILEID(inode), req->wb_bytes,
                (long long)req_offset(req));
 
+       if (nfs_error_is_fatal_on_server(error) && error != -ETIMEDOUT)
+               SetPageError(page);
        if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
-               if (PageUptodate(req->wb_page))
-                       nfs_readpage_to_fscache(inode, req->wb_page, 0);
+               struct address_space *mapping = page_file_mapping(page);
 
-               unlock_page(req->wb_page);
+               if (PageUptodate(page))
+                       nfs_readpage_to_fscache(inode, page, 0);
+               else if (!PageError(page) && !PagePrivate(page))
+                       generic_error_remove_page(mapping, page);
+               unlock_page(page);
        }
        nfs_release_request(req);
 }
@@ -131,7 +137,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
                             &nfs_async_read_completion_ops);
        if (!nfs_pageio_add_request(&pgio, new)) {
                nfs_list_remove_request(new);
-               nfs_readpage_release(new);
+               nfs_readpage_release(new, pgio.pg_error);
        }
        nfs_pageio_complete(&pgio);
 
@@ -153,6 +159,7 @@ static void nfs_page_group_set_uptodate(struct nfs_page *req)
 static void nfs_read_completion(struct nfs_pgio_header *hdr)
 {
        unsigned long bytes = 0;
+       int error;
 
        if (test_bit(NFS_IOHDR_REDO, &hdr->flags))
                goto out;
@@ -179,14 +186,19 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
                                zero_user_segment(page, start, end);
                        }
                }
+               error = 0;
                bytes += req->wb_bytes;
                if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
                        if (bytes <= hdr->good_bytes)
                                nfs_page_group_set_uptodate(req);
+                       else {
+                               error = hdr->error;
+                               xchg(&nfs_req_openctx(req)->error, error);
+                       }
                } else
                        nfs_page_group_set_uptodate(req);
                nfs_list_remove_request(req);
-               nfs_readpage_release(req);
+               nfs_readpage_release(req, error);
        }
 out:
        hdr->release(hdr);
@@ -213,7 +225,7 @@ nfs_async_read_error(struct list_head *head, int error)
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);
                nfs_list_remove_request(req);
-               nfs_readpage_release(req);
+               nfs_readpage_release(req, error);
        }
 }
 
@@ -337,8 +349,13 @@ int nfs_readpage(struct file *file, struct page *page)
                        goto out;
        }
 
+       xchg(&ctx->error, 0);
        error = nfs_readpage_async(ctx, inode, page);
-
+       if (!error) {
+               error = wait_on_page_locked_killable(page);
+               if (!PageUptodate(page) && !error)
+                       error = xchg(&ctx->error, 0);
+       }
 out:
        put_nfs_open_context(ctx);
        return error;
@@ -372,8 +389,8 @@ readpage_async_filler(void *data, struct page *page)
                zero_user_segment(page, len, PAGE_SIZE);
        if (!nfs_pageio_add_request(desc->pgio, new)) {
                nfs_list_remove_request(new);
-               nfs_readpage_release(new);
                error = desc->pgio->pg_error;
+               nfs_readpage_release(new, error);
                goto out;
        }
        return 0;
index 92d9cad..85ca495 100644 (file)
@@ -57,6 +57,7 @@ static const struct rpc_call_ops nfs_commit_ops;
 static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops;
 static const struct nfs_commit_completion_ops nfs_commit_completion_ops;
 static const struct nfs_rw_ops nfs_rw_write_ops;
+static void nfs_inode_remove_request(struct nfs_page *req);
 static void nfs_clear_request_commit(struct nfs_page *req);
 static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo,
                                      struct inode *inode);
@@ -591,23 +592,13 @@ release_request:
 
 static void nfs_write_error(struct nfs_page *req, int error)
 {
+       nfs_set_pageerror(page_file_mapping(req->wb_page));
        nfs_mapping_set_error(req->wb_page, error);
+       nfs_inode_remove_request(req);
        nfs_end_page_writeback(req);
        nfs_release_request(req);
 }
 
-static bool
-nfs_error_is_fatal_on_server(int err)
-{
-       switch (err) {
-       case 0:
-       case -ERESTARTSYS:
-       case -EINTR:
-               return false;
-       }
-       return nfs_error_is_fatal(err);
-}
-
 /*
  * Find an associated nfs write request, and prepare to flush it out
  * May return an error if the user signalled nfs_wait_on_request().
@@ -615,7 +606,6 @@ nfs_error_is_fatal_on_server(int err)
 static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
                                struct page *page)
 {
-       struct address_space *mapping;
        struct nfs_page *req;
        int ret = 0;
 
@@ -630,12 +620,11 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
        WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags));
 
        /* If there is a fatal error that covers this write, just exit */
-       ret = 0;
-       mapping = page_file_mapping(page);
-       if (test_bit(AS_ENOSPC, &mapping->flags) ||
-           test_bit(AS_EIO, &mapping->flags))
+       ret = pgio->pg_error;
+       if (nfs_error_is_fatal_on_server(ret))
                goto out_launder;
 
+       ret = 0;
        if (!nfs_pageio_add_request(pgio, req)) {
                ret = pgio->pg_error;
                /*
@@ -647,6 +636,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
                } else
                        ret = -EAGAIN;
                nfs_redirty_request(req);
+               pgio->pg_error = 0;
        } else
                nfs_add_stats(page_file_mapping(page)->host,
                                NFSIOS_WRITEPAGES, 1);
@@ -666,7 +656,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc,
        ret = nfs_page_async_flush(pgio, page);
        if (ret == -EAGAIN) {
                redirty_page_for_writepage(wbc, page);
-               ret = 0;
+               ret = AOP_WRITEPAGE_ACTIVATE;
        }
        return ret;
 }
@@ -685,10 +675,11 @@ static int nfs_writepage_locked(struct page *page,
        nfs_pageio_init_write(&pgio, inode, 0,
                                false, &nfs_async_write_completion_ops);
        err = nfs_do_writepage(page, wbc, &pgio);
+       pgio.pg_error = 0;
        nfs_pageio_complete(&pgio);
        if (err < 0)
                return err;
-       if (pgio.pg_error < 0)
+       if (nfs_error_is_fatal(pgio.pg_error))
                return pgio.pg_error;
        return 0;
 }
@@ -698,7 +689,8 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
        int ret;
 
        ret = nfs_writepage_locked(page, wbc);
-       unlock_page(page);
+       if (ret != AOP_WRITEPAGE_ACTIVATE)
+               unlock_page(page);
        return ret;
 }
 
@@ -707,7 +699,8 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
        int ret;
 
        ret = nfs_do_writepage(page, wbc, data);
-       unlock_page(page);
+       if (ret != AOP_WRITEPAGE_ACTIVATE)
+               unlock_page(page);
        return ret;
 }
 
@@ -733,13 +726,14 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
                                &nfs_async_write_completion_ops);
        pgio.pg_io_completion = ioc;
        err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
+       pgio.pg_error = 0;
        nfs_pageio_complete(&pgio);
        nfs_io_completion_put(ioc);
 
        if (err < 0)
                goto out_err;
        err = pgio.pg_error;
-       if (err < 0)
+       if (nfs_error_is_fatal(err))
                goto out_err;
        return 0;
 out_err:
index 26ad75a..96352ab 100644 (file)
@@ -571,7 +571,7 @@ nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data)
  */
 static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v)
 {
-       struct nfsd_net *nn = v;
+       struct nfsd_net *nn = m->private;
 
        seq_printf(m, "max entries:           %u\n", nn->max_drc_entries);
        seq_printf(m, "num entries:           %u\n",
index 13c5487..3cf4f6a 100644 (file)
@@ -1171,13 +1171,17 @@ static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
        return inode;
 }
 
-static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, struct nfsdfs_client *ncl)
 {
        struct inode *inode;
 
        inode = nfsd_get_inode(dir->i_sb, mode);
        if (!inode)
                return -ENOMEM;
+       if (ncl) {
+               inode->i_private = ncl;
+               kref_get(&ncl->cl_ref);
+       }
        d_add(dentry, inode);
        inc_nlink(dir);
        fsnotify_mkdir(dir, dentry);
@@ -1194,17 +1198,14 @@ static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *nc
        dentry = d_alloc_name(parent, name);
        if (!dentry)
                goto out_err;
-       ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600);
+       ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600, ncl);
        if (ret)
                goto out_err;
-       if (ncl) {
-               d_inode(dentry)->i_private = ncl;
-               kref_get(&ncl->cl_ref);
-       }
 out:
        inode_unlock(dir);
        return dentry;
 out_err:
+       dput(dentry);
        dentry = ERR_PTR(ret);
        goto out;
 }
@@ -1214,11 +1215,9 @@ static void clear_ncl(struct inode *inode)
        struct nfsdfs_client *ncl = inode->i_private;
 
        inode->i_private = NULL;
-       synchronize_rcu();
        kref_put(&ncl->cl_ref, ncl->cl_release);
 }
 
-
 static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
 {
        struct nfsdfs_client *nc = inode->i_private;
@@ -1232,9 +1231,9 @@ struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
 {
        struct nfsdfs_client *nc;
 
-       rcu_read_lock();
+       inode_lock_shared(inode);
        nc = __get_nfsdfs_client(inode);
-       rcu_read_unlock();
+       inode_unlock_shared(inode);
        return nc;
 }
 /* from __rpc_unlink */
index 1f5088d..5bbf587 100644 (file)
@@ -1811,10 +1811,7 @@ static int generic_remap_check_len(struct inode *inode_in,
        return (remap_flags & REMAP_FILE_DEDUP) ? -EBADE : -EINVAL;
 }
 
-/*
- * Read a page's worth of file data into the page cache.  Return the page
- * locked.
- */
+/* Read a page's worth of file data into the page cache. */
 static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
 {
        struct page *page;
@@ -1826,10 +1823,32 @@ static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
                put_page(page);
                return ERR_PTR(-EIO);
        }
-       lock_page(page);
        return page;
 }
 
+/*
+ * Lock two pages, ensuring that we lock in offset order if the pages are from
+ * the same file.
+ */
+static void vfs_lock_two_pages(struct page *page1, struct page *page2)
+{
+       /* Always lock in order of increasing index. */
+       if (page1->index > page2->index)
+               swap(page1, page2);
+
+       lock_page(page1);
+       if (page1 != page2)
+               lock_page(page2);
+}
+
+/* Unlock two pages, being careful not to unlock the same page twice. */
+static void vfs_unlock_two_pages(struct page *page1, struct page *page2)
+{
+       unlock_page(page1);
+       if (page1 != page2)
+               unlock_page(page2);
+}
+
 /*
  * Compare extents of two files to see if they are the same.
  * Caller must have locked both inodes to prevent write races.
@@ -1867,10 +1886,24 @@ static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
                dest_page = vfs_dedupe_get_page(dest, destoff);
                if (IS_ERR(dest_page)) {
                        error = PTR_ERR(dest_page);
-                       unlock_page(src_page);
                        put_page(src_page);
                        goto out_error;
                }
+
+               vfs_lock_two_pages(src_page, dest_page);
+
+               /*
+                * Now that we've locked both pages, make sure they're still
+                * mapped to the file data we're interested in.  If not,
+                * someone is invalidating pages on us and we lose.
+                */
+               if (!PageUptodate(src_page) || !PageUptodate(dest_page) ||
+                   src_page->mapping != src->i_mapping ||
+                   dest_page->mapping != dest->i_mapping) {
+                       same = false;
+                       goto unlock;
+               }
+
                src_addr = kmap_atomic(src_page);
                dest_addr = kmap_atomic(dest_page);
 
@@ -1882,8 +1915,8 @@ static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 
                kunmap_atomic(dest_addr);
                kunmap_atomic(src_addr);
-               unlock_page(dest_page);
-               unlock_page(src_page);
+unlock:
+               vfs_unlock_two_pages(src_page, dest_page);
                put_page(dest_page);
                put_page(src_page);
 
index 04f0968..1600034 100644 (file)
@@ -119,6 +119,7 @@ static int traverse(struct seq_file *m, loff_t offset)
                }
                if (seq_has_overflowed(m))
                        goto Eoverflow;
+               p = m->op->next(m, p, &m->index);
                if (pos + m->count > offset) {
                        m->from = offset - pos;
                        m->count -= m->from;
@@ -126,7 +127,6 @@ static int traverse(struct seq_file *m, loff_t offset)
                }
                pos += m->count;
                m->count = 0;
-               p = m->op->next(m, p, &m->index);
                if (pos == offset)
                        break;
        }
index 80d7301..c0b84e9 100644 (file)
@@ -51,7 +51,7 @@
 static void shrink_liability(struct ubifs_info *c, int nr_to_write)
 {
        down_read(&c->vfs_sb->s_umount);
-       writeback_inodes_sb(c->vfs_sb, WB_REASON_FS_FREE_SPACE);
+       writeback_inodes_sb_nr(c->vfs_sb, nr_to_write, WB_REASON_FS_FREE_SPACE);
        up_read(&c->vfs_sb->s_umount);
 }
 
index b52624e..3b4b411 100644 (file)
@@ -129,7 +129,6 @@ static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o)
 static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph)
 {
        if (orph->del) {
-               spin_unlock(&c->orphan_lock);
                dbg_gen("deleted twice ino %lu", orph->inum);
                return;
        }
@@ -138,7 +137,6 @@ static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph)
                orph->del = 1;
                orph->dnext = c->orph_dnext;
                c->orph_dnext = orph;
-               spin_unlock(&c->orphan_lock);
                dbg_gen("delete later ino %lu", orph->inum);
                return;
        }
index 2c0803b..8c1d571 100644 (file)
@@ -609,6 +609,10 @@ static int init_constants_early(struct ubifs_info *c)
        c->max_bu_buf_len = UBIFS_MAX_BULK_READ * UBIFS_MAX_DATA_NODE_SZ;
        if (c->max_bu_buf_len > c->leb_size)
                c->max_bu_buf_len = c->leb_size;
+
+       /* Log is ready, preserve one LEB for commits. */
+       c->min_log_bytes = c->leb_size;
+
        return 0;
 }
 
index ccbdbd6..fe6d804 100644 (file)
@@ -880,6 +880,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
        /* len == 0 means wake all */
        struct userfaultfd_wake_range range = { .len = 0, };
        unsigned long new_flags;
+       bool still_valid;
 
        WRITE_ONCE(ctx->released, true);
 
@@ -895,8 +896,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
         * taking the mmap_sem for writing.
         */
        down_write(&mm->mmap_sem);
-       if (!mmget_still_valid(mm))
-               goto skip_mm;
+       still_valid = mmget_still_valid(mm);
        prev = NULL;
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
                cond_resched();
@@ -907,19 +907,20 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
                        continue;
                }
                new_flags = vma->vm_flags & ~(VM_UFFD_MISSING | VM_UFFD_WP);
-               prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
-                                new_flags, vma->anon_vma,
-                                vma->vm_file, vma->vm_pgoff,
-                                vma_policy(vma),
-                                NULL_VM_UFFD_CTX);
-               if (prev)
-                       vma = prev;
-               else
-                       prev = vma;
+               if (still_valid) {
+                       prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end,
+                                        new_flags, vma->anon_vma,
+                                        vma->vm_file, vma->vm_pgoff,
+                                        vma_policy(vma),
+                                        NULL_VM_UFFD_CTX);
+                       if (prev)
+                               vma = prev;
+                       else
+                               prev = vma;
+               }
                vma->vm_flags = new_flags;
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
        }
-skip_mm:
        up_write(&mm->mmap_sem);
        mmput(mm);
 wakeup:
index baf0b72..07aad70 100644 (file)
@@ -3835,15 +3835,28 @@ xfs_bmapi_read(
        XFS_STATS_INC(mp, xs_blk_mapr);
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
+       if (!ifp) {
+               /* No CoW fork?  Return a hole. */
+               if (whichfork == XFS_COW_FORK) {
+                       mval->br_startoff = bno;
+                       mval->br_startblock = HOLESTARTBLOCK;
+                       mval->br_blockcount = len;
+                       mval->br_state = XFS_EXT_NORM;
+                       *nmap = 1;
+                       return 0;
+               }
 
-       /* No CoW fork?  Return a hole. */
-       if (whichfork == XFS_COW_FORK && !ifp) {
-               mval->br_startoff = bno;
-               mval->br_startblock = HOLESTARTBLOCK;
-               mval->br_blockcount = len;
-               mval->br_state = XFS_EXT_NORM;
-               *nmap = 1;
-               return 0;
+               /*
+                * A missing attr ifork implies that the inode says we're in
+                * extents or btree format but failed to pass the inode fork
+                * verifier while trying to load it.  Treat that as a file
+                * corruption too.
+                */
+#ifdef DEBUG
+               xfs_alert(mp, "%s: inode %llu missing fork %d",
+                               __func__, ip->i_ino, whichfork);
+#endif /* DEBUG */
+               return -EFSCORRUPTED;
        }
 
        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
index d1c77fd..0bf56e9 100644 (file)
@@ -487,10 +487,8 @@ xfs_da3_split(
        ASSERT(state->path.active == 0);
        oldblk = &state->path.blk[0];
        error = xfs_da3_root_split(state, oldblk, addblk);
-       if (error) {
-               addblk->bp = NULL;
-               return error;   /* GROT: dir is inconsistent */
-       }
+       if (error)
+               goto out;
 
        /*
         * Update pointers to the node which used to be block 0 and just got
@@ -505,7 +503,10 @@ xfs_da3_split(
         */
        node = oldblk->bp->b_addr;
        if (node->hdr.info.forw) {
-               ASSERT(be32_to_cpu(node->hdr.info.forw) == addblk->blkno);
+               if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
                node = addblk->bp->b_addr;
                node->hdr.info.back = cpu_to_be32(oldblk->blkno);
                xfs_trans_log_buf(state->args->trans, addblk->bp,
@@ -514,15 +515,19 @@ xfs_da3_split(
        }
        node = oldblk->bp->b_addr;
        if (node->hdr.info.back) {
-               ASSERT(be32_to_cpu(node->hdr.info.back) == addblk->blkno);
+               if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
                node = addblk->bp->b_addr;
                node->hdr.info.forw = cpu_to_be32(oldblk->blkno);
                xfs_trans_log_buf(state->args->trans, addblk->bp,
                                  XFS_DA_LOGRANGE(node, &node->hdr.info,
                                  sizeof(node->hdr.info)));
        }
+out:
        addblk->bp = NULL;
-       return 0;
+       return error;
 }
 
 /*
index afcc664..1fc44ef 100644 (file)
@@ -741,7 +741,8 @@ xfs_dir2_leafn_lookup_for_entry(
        ents = dp->d_ops->leaf_ents_p(leaf);
 
        xfs_dir3_leaf_check(dp, bp);
-       ASSERT(leafhdr.count > 0);
+       if (leafhdr.count <= 0)
+               return -EFSCORRUPTED;
 
        /*
         * Look up the hash value in the leaf entries.
index 7fcf756..7bd7534 100644 (file)
@@ -547,63 +547,12 @@ xfs_file_compat_ioctl(
        struct inode            *inode = file_inode(filp);
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       void                    __user *arg = (void __user *)p;
+       void                    __user *arg = compat_ptr(p);
        int                     error;
 
        trace_xfs_file_compat_ioctl(ip);
 
        switch (cmd) {
-       /* No size or alignment issues on any arch */
-       case XFS_IOC_DIOINFO:
-       case XFS_IOC_FSGEOMETRY_V4:
-       case XFS_IOC_FSGEOMETRY:
-       case XFS_IOC_AG_GEOMETRY:
-       case XFS_IOC_FSGETXATTR:
-       case XFS_IOC_FSSETXATTR:
-       case XFS_IOC_FSGETXATTRA:
-       case XFS_IOC_FSSETDM:
-       case XFS_IOC_GETBMAP:
-       case XFS_IOC_GETBMAPA:
-       case XFS_IOC_GETBMAPX:
-       case XFS_IOC_FSCOUNTS:
-       case XFS_IOC_SET_RESBLKS:
-       case XFS_IOC_GET_RESBLKS:
-       case XFS_IOC_FSGROWFSLOG:
-       case XFS_IOC_GOINGDOWN:
-       case XFS_IOC_ERROR_INJECTION:
-       case XFS_IOC_ERROR_CLEARALL:
-       case FS_IOC_GETFSMAP:
-       case XFS_IOC_SCRUB_METADATA:
-       case XFS_IOC_BULKSTAT:
-       case XFS_IOC_INUMBERS:
-               return xfs_file_ioctl(filp, cmd, p);
-#if !defined(BROKEN_X86_ALIGNMENT) || defined(CONFIG_X86_X32)
-       /*
-        * These are handled fine if no alignment issues.  To support x32
-        * which uses native 64-bit alignment we must emit these cases in
-        * addition to the ia-32 compat set below.
-        */
-       case XFS_IOC_ALLOCSP:
-       case XFS_IOC_FREESP:
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_ALLOCSP64:
-       case XFS_IOC_FREESP64:
-       case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP64:
-       case XFS_IOC_FSGEOMETRY_V1:
-       case XFS_IOC_FSGROWFSDATA:
-       case XFS_IOC_FSGROWFSRT:
-       case XFS_IOC_ZERO_RANGE:
-#ifdef CONFIG_X86_X32
-       /*
-        * x32 special: this gets a different cmd number from the ia-32 compat
-        * case below; the associated data will match native 64-bit alignment.
-        */
-       case XFS_IOC_SWAPEXT:
-#endif
-               return xfs_file_ioctl(filp, cmd, p);
-#endif
 #if defined(BROKEN_X86_ALIGNMENT)
        case XFS_IOC_ALLOCSP_32:
        case XFS_IOC_FREESP_32:
@@ -705,6 +654,7 @@ xfs_file_compat_ioctl(
        case XFS_IOC_FSSETDM_BY_HANDLE_32:
                return xfs_compat_fssetdm_by_handle(filp, arg);
        default:
-               return -ENOIOCTLCMD;
+               /* try the native version */
+               return xfs_file_ioctl(filp, cmd, (unsigned long)arg);
        }
 }
index ff3c1fa..fe285d1 100644 (file)
@@ -793,6 +793,7 @@ xfs_setattr_nonsize(
 
 out_cancel:
        xfs_trans_cancel(tp);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 out_dqrele:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
index 00e9f5c..7fc3c1a 100644 (file)
@@ -429,10 +429,7 @@ xfs_log_reserve(
 
        ASSERT(*ticp == NULL);
        tic = xlog_ticket_alloc(log, unit_bytes, cnt, client, permanent,
-                               KM_SLEEP | KM_MAYFAIL);
-       if (!tic)
-               return -ENOMEM;
-
+                               KM_SLEEP);
        *ticp = tic;
 
        xlog_grant_push_ail(log, tic->t_cnt ? tic->t_unit_res * tic->t_cnt
index 0c954ca..a339bd5 100644 (file)
@@ -32,7 +32,7 @@ xfs_break_leased_layouts(
        struct xfs_inode        *ip = XFS_I(inode);
        int                     error;
 
-       while ((error = break_layout(inode, false) == -EWOULDBLOCK)) {
+       while ((error = break_layout(inode, false)) == -EWOULDBLOCK) {
                xfs_iunlock(ip, *iolock);
                *did_unlock = true;
                error = break_layout(inode, true);
index c4ec7af..edbe37b 100644 (file)
@@ -1190,11 +1190,11 @@ xfs_reflink_remap_blocks(
 }
 
 /*
- * Grab the exclusive iolock for a data copy from src to dest, making
- * sure to abide vfs locking order (lowest pointer value goes first) and
- * breaking the pnfs layout leases on dest before proceeding.  The loop
- * is needed because we cannot call the blocking break_layout() with the
- * src iolock held, and therefore have to back out both locks.
+ * Grab the exclusive iolock for a data copy from src to dest, making sure to
+ * abide vfs locking order (lowest pointer value goes first) and breaking the
+ * layout leases before proceeding.  The loop is needed because we cannot call
+ * the blocking break_layout() with the iolocks held, and therefore have to
+ * back out both locks.
  */
 static int
 xfs_iolock_two_inodes_and_break_layout(
@@ -1203,33 +1203,44 @@ xfs_iolock_two_inodes_and_break_layout(
 {
        int                     error;
 
-retry:
-       if (src < dest) {
-               inode_lock_shared(src);
-               inode_lock_nested(dest, I_MUTEX_NONDIR2);
-       } else {
-               /* src >= dest */
-               inode_lock(dest);
-       }
+       if (src > dest)
+               swap(src, dest);
 
-       error = break_layout(dest, false);
-       if (error == -EWOULDBLOCK) {
-               inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+retry:
+       /* Wait to break both inodes' layouts before we start locking. */
+       error = break_layout(src, true);
+       if (error)
+               return error;
+       if (src != dest) {
                error = break_layout(dest, true);
                if (error)
                        return error;
-               goto retry;
        }
+
+       /* Lock one inode and make sure nobody got in and leased it. */
+       inode_lock(src);
+       error = break_layout(src, false);
        if (error) {
+               inode_unlock(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
+               return error;
+       }
+
+       if (src == dest)
+               return 0;
+
+       /* Lock the other inode and make sure nobody got in and leased it. */
+       inode_lock_nested(dest, I_MUTEX_NONDIR2);
+       error = break_layout(dest, false);
+       if (error) {
+               inode_unlock(src);
                inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
                return error;
        }
-       if (src > dest)
-               inode_lock_shared_nested(src, I_MUTEX_NONDIR2);
+
        return 0;
 }
 
@@ -1247,10 +1258,10 @@ xfs_reflink_remap_unlock(
 
        xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
        if (!same_inode)
-               xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
+               xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
        inode_unlock(inode_out);
        if (!same_inode)
-               inode_unlock_shared(inode_in);
+               inode_unlock(inode_in);
 }
 
 /*
@@ -1325,7 +1336,7 @@ xfs_reflink_remap_prep(
        if (same_inode)
                xfs_ilock(src, XFS_MMAPLOCK_EXCL);
        else
-               xfs_lock_two_inodes(src, XFS_MMAPLOCK_SHARED, dest,
+               xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
                                XFS_MMAPLOCK_EXCL);
 
        /* Check file eligibility and prepare for block sharing. */
index bb6cb34..f6947da 100644 (file)
 
 #define p4d_alloc(mm, pgd, address)    (pgd)
 #define p4d_offset(pgd, start)         (pgd)
-#define p4d_none(p4d)                  0
-#define p4d_bad(p4d)                   0
-#define p4d_present(p4d)               1
+
+#ifndef __ASSEMBLY__
+static inline int p4d_none(p4d_t p4d)
+{
+       return 0;
+}
+
+static inline int p4d_bad(p4d_t p4d)
+{
+       return 0;
+}
+
+static inline int p4d_present(p4d_t p4d)
+{
+       return 1;
+}
+#endif
+
 #define p4d_ERROR(p4d)                 do { } while (0)
 #define p4d_clear(p4d)                 pgd_clear(p4d)
 #define p4d_val(p4d)                   pgd_val(p4d)
index 95a159a..80ca610 100644 (file)
@@ -16,6 +16,8 @@ struct error_injection_entry {
        int             etype;
 };
 
+struct pt_regs;
+
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 /*
  * Whitelist ganerating macro. Specify functions which can be
@@ -28,8 +30,12 @@ static struct error_injection_entry __used                           \
                .addr = (unsigned long)fname,                           \
                .etype = EI_ETYPE_##_etype,                             \
        };
+
+void override_function_with_return(struct pt_regs *regs);
 #else
 #define ALLOW_ERROR_INJECTION(fname, _etype)
+
+static inline void override_function_with_return(struct pt_regs *regs) { }
 #endif
 #endif
 
diff --git a/include/dt-bindings/memory/mt8183-larb-port.h b/include/dt-bindings/memory/mt8183-larb-port.h
new file mode 100644 (file)
index 0000000..2c579f3
--- /dev/null
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ */
+#ifndef __DTS_IOMMU_PORT_MT8183_H
+#define __DTS_IOMMU_PORT_MT8183_H
+
+#define MTK_M4U_ID(larb, port)         (((larb) << 5) | (port))
+
+#define M4U_LARB0_ID                   0
+#define M4U_LARB1_ID                   1
+#define M4U_LARB2_ID                   2
+#define M4U_LARB3_ID                   3
+#define M4U_LARB4_ID                   4
+#define M4U_LARB5_ID                   5
+#define M4U_LARB6_ID                   6
+#define M4U_LARB7_ID                   7
+
+/* larb0 */
+#define        M4U_PORT_DISP_OVL0              MTK_M4U_ID(M4U_LARB0_ID, 0)
+#define        M4U_PORT_DISP_2L_OVL0_LARB0     MTK_M4U_ID(M4U_LARB0_ID, 1)
+#define        M4U_PORT_DISP_2L_OVL1_LARB0     MTK_M4U_ID(M4U_LARB0_ID, 2)
+#define        M4U_PORT_DISP_RDMA0             MTK_M4U_ID(M4U_LARB0_ID, 3)
+#define        M4U_PORT_DISP_RDMA1             MTK_M4U_ID(M4U_LARB0_ID, 4)
+#define        M4U_PORT_DISP_WDMA0             MTK_M4U_ID(M4U_LARB0_ID, 5)
+#define        M4U_PORT_MDP_RDMA0              MTK_M4U_ID(M4U_LARB0_ID, 6)
+#define        M4U_PORT_MDP_WROT0              MTK_M4U_ID(M4U_LARB0_ID, 7)
+#define        M4U_PORT_MDP_WDMA0              MTK_M4U_ID(M4U_LARB0_ID, 8)
+#define        M4U_PORT_DISP_FAKE0             MTK_M4U_ID(M4U_LARB0_ID, 9)
+
+/* larb1 */
+#define        M4U_PORT_HW_VDEC_MC_EXT         MTK_M4U_ID(M4U_LARB1_ID, 0)
+#define        M4U_PORT_HW_VDEC_PP_EXT         MTK_M4U_ID(M4U_LARB1_ID, 1)
+#define        M4U_PORT_HW_VDEC_VLD_EXT        MTK_M4U_ID(M4U_LARB1_ID, 2)
+#define        M4U_PORT_HW_VDEC_AVC_MV_EXT     MTK_M4U_ID(M4U_LARB1_ID, 3)
+#define        M4U_PORT_HW_VDEC_PRED_RD_EXT    MTK_M4U_ID(M4U_LARB1_ID, 4)
+#define        M4U_PORT_HW_VDEC_PRED_WR_EXT    MTK_M4U_ID(M4U_LARB1_ID, 5)
+#define        M4U_PORT_HW_VDEC_PPWRAP_EXT     MTK_M4U_ID(M4U_LARB1_ID, 6)
+
+/* larb2 VPU0 */
+#define        M4U_PORT_IMG_IPUO               MTK_M4U_ID(M4U_LARB2_ID, 0)
+#define        M4U_PORT_IMG_IPU3O              MTK_M4U_ID(M4U_LARB2_ID, 1)
+#define        M4U_PORT_IMG_IPUI               MTK_M4U_ID(M4U_LARB2_ID, 2)
+
+/* larb3 VPU1 */
+#define        M4U_PORT_CAM_IPUO               MTK_M4U_ID(M4U_LARB3_ID, 0)
+#define        M4U_PORT_CAM_IPU2O              MTK_M4U_ID(M4U_LARB3_ID, 1)
+#define        M4U_PORT_CAM_IPU3O              MTK_M4U_ID(M4U_LARB3_ID, 2)
+#define        M4U_PORT_CAM_IPUI               MTK_M4U_ID(M4U_LARB3_ID, 3)
+#define        M4U_PORT_CAM_IPU2I              MTK_M4U_ID(M4U_LARB3_ID, 4)
+
+/* larb4 */
+#define        M4U_PORT_VENC_RCPU              MTK_M4U_ID(M4U_LARB4_ID, 0)
+#define        M4U_PORT_VENC_REC               MTK_M4U_ID(M4U_LARB4_ID, 1)
+#define        M4U_PORT_VENC_BSDMA             MTK_M4U_ID(M4U_LARB4_ID, 2)
+#define        M4U_PORT_VENC_SV_COMV           MTK_M4U_ID(M4U_LARB4_ID, 3)
+#define        M4U_PORT_VENC_RD_COMV           MTK_M4U_ID(M4U_LARB4_ID, 4)
+#define        M4U_PORT_JPGENC_RDMA            MTK_M4U_ID(M4U_LARB4_ID, 5)
+#define        M4U_PORT_JPGENC_BSDMA           MTK_M4U_ID(M4U_LARB4_ID, 6)
+#define        M4U_PORT_VENC_CUR_LUMA          MTK_M4U_ID(M4U_LARB4_ID, 7)
+#define        M4U_PORT_VENC_CUR_CHROMA        MTK_M4U_ID(M4U_LARB4_ID, 8)
+#define        M4U_PORT_VENC_REF_LUMA          MTK_M4U_ID(M4U_LARB4_ID, 9)
+#define        M4U_PORT_VENC_REF_CHROMA        MTK_M4U_ID(M4U_LARB4_ID, 10)
+
+/* larb5 */
+#define        M4U_PORT_CAM_IMGI               MTK_M4U_ID(M4U_LARB5_ID, 0)
+#define        M4U_PORT_CAM_IMG2O              MTK_M4U_ID(M4U_LARB5_ID, 1)
+#define        M4U_PORT_CAM_IMG3O              MTK_M4U_ID(M4U_LARB5_ID, 2)
+#define        M4U_PORT_CAM_VIPI               MTK_M4U_ID(M4U_LARB5_ID, 3)
+#define        M4U_PORT_CAM_LCEI               MTK_M4U_ID(M4U_LARB5_ID, 4)
+#define        M4U_PORT_CAM_SMXI               MTK_M4U_ID(M4U_LARB5_ID, 5)
+#define        M4U_PORT_CAM_SMXO               MTK_M4U_ID(M4U_LARB5_ID, 6)
+#define        M4U_PORT_CAM_WPE0_RDMA1         MTK_M4U_ID(M4U_LARB5_ID, 7)
+#define        M4U_PORT_CAM_WPE0_RDMA0         MTK_M4U_ID(M4U_LARB5_ID, 8)
+#define        M4U_PORT_CAM_WPE0_WDMA          MTK_M4U_ID(M4U_LARB5_ID, 9)
+#define        M4U_PORT_CAM_FDVT_RP            MTK_M4U_ID(M4U_LARB5_ID, 10)
+#define        M4U_PORT_CAM_FDVT_WR            MTK_M4U_ID(M4U_LARB5_ID, 11)
+#define        M4U_PORT_CAM_FDVT_RB            MTK_M4U_ID(M4U_LARB5_ID, 12)
+#define        M4U_PORT_CAM_WPE1_RDMA0         MTK_M4U_ID(M4U_LARB5_ID, 13)
+#define        M4U_PORT_CAM_WPE1_RDMA1         MTK_M4U_ID(M4U_LARB5_ID, 14)
+#define        M4U_PORT_CAM_WPE1_WDMA          MTK_M4U_ID(M4U_LARB5_ID, 15)
+#define        M4U_PORT_CAM_DPE_RDMA           MTK_M4U_ID(M4U_LARB5_ID, 16)
+#define        M4U_PORT_CAM_DPE_WDMA           MTK_M4U_ID(M4U_LARB5_ID, 17)
+#define        M4U_PORT_CAM_MFB_RDMA0          MTK_M4U_ID(M4U_LARB5_ID, 18)
+#define        M4U_PORT_CAM_MFB_RDMA1          MTK_M4U_ID(M4U_LARB5_ID, 19)
+#define        M4U_PORT_CAM_MFB_WDMA           MTK_M4U_ID(M4U_LARB5_ID, 20)
+#define        M4U_PORT_CAM_RSC_RDMA0          MTK_M4U_ID(M4U_LARB5_ID, 21)
+#define        M4U_PORT_CAM_RSC_WDMA           MTK_M4U_ID(M4U_LARB5_ID, 22)
+#define        M4U_PORT_CAM_OWE_RDMA           MTK_M4U_ID(M4U_LARB5_ID, 23)
+#define        M4U_PORT_CAM_OWE_WDMA           MTK_M4U_ID(M4U_LARB5_ID, 24)
+
+/* larb6 */
+#define        M4U_PORT_CAM_IMGO               MTK_M4U_ID(M4U_LARB6_ID, 0)
+#define        M4U_PORT_CAM_RRZO               MTK_M4U_ID(M4U_LARB6_ID, 1)
+#define        M4U_PORT_CAM_AAO                MTK_M4U_ID(M4U_LARB6_ID, 2)
+#define        M4U_PORT_CAM_AFO                MTK_M4U_ID(M4U_LARB6_ID, 3)
+#define        M4U_PORT_CAM_LSCI0              MTK_M4U_ID(M4U_LARB6_ID, 4)
+#define        M4U_PORT_CAM_LSCI1              MTK_M4U_ID(M4U_LARB6_ID, 5)
+#define        M4U_PORT_CAM_PDO                MTK_M4U_ID(M4U_LARB6_ID, 6)
+#define        M4U_PORT_CAM_BPCI               MTK_M4U_ID(M4U_LARB6_ID, 7)
+#define        M4U_PORT_CAM_LCSO               MTK_M4U_ID(M4U_LARB6_ID, 8)
+#define        M4U_PORT_CAM_CAM_RSSO_A         MTK_M4U_ID(M4U_LARB6_ID, 9)
+#define        M4U_PORT_CAM_UFEO               MTK_M4U_ID(M4U_LARB6_ID, 10)
+#define        M4U_PORT_CAM_SOCO               MTK_M4U_ID(M4U_LARB6_ID, 11)
+#define        M4U_PORT_CAM_SOC1               MTK_M4U_ID(M4U_LARB6_ID, 12)
+#define        M4U_PORT_CAM_SOC2               MTK_M4U_ID(M4U_LARB6_ID, 13)
+#define        M4U_PORT_CAM_CCUI               MTK_M4U_ID(M4U_LARB6_ID, 14)
+#define        M4U_PORT_CAM_CCUO               MTK_M4U_ID(M4U_LARB6_ID, 15)
+#define        M4U_PORT_CAM_RAWI_A             MTK_M4U_ID(M4U_LARB6_ID, 16)
+#define        M4U_PORT_CAM_CCUG               MTK_M4U_ID(M4U_LARB6_ID, 17)
+#define        M4U_PORT_CAM_PSO                MTK_M4U_ID(M4U_LARB6_ID, 18)
+#define        M4U_PORT_CAM_AFO_1              MTK_M4U_ID(M4U_LARB6_ID, 19)
+#define        M4U_PORT_CAM_LSCI_2             MTK_M4U_ID(M4U_LARB6_ID, 20)
+#define        M4U_PORT_CAM_PDI                MTK_M4U_ID(M4U_LARB6_ID, 21)
+#define        M4U_PORT_CAM_FLKO               MTK_M4U_ID(M4U_LARB6_ID, 22)
+#define        M4U_PORT_CAM_LMVO               MTK_M4U_ID(M4U_LARB6_ID, 23)
+#define        M4U_PORT_CAM_UFGO               MTK_M4U_ID(M4U_LARB6_ID, 24)
+#define        M4U_PORT_CAM_SPARE              MTK_M4U_ID(M4U_LARB6_ID, 25)
+#define        M4U_PORT_CAM_SPARE_2            MTK_M4U_ID(M4U_LARB6_ID, 26)
+#define        M4U_PORT_CAM_SPARE_3            MTK_M4U_ID(M4U_LARB6_ID, 27)
+#define        M4U_PORT_CAM_SPARE_4            MTK_M4U_ID(M4U_LARB6_ID, 28)
+#define        M4U_PORT_CAM_SPARE_5            MTK_M4U_ID(M4U_LARB6_ID, 29)
+#define        M4U_PORT_CAM_SPARE_6            MTK_M4U_ID(M4U_LARB6_ID, 30)
+
+/* CCU */
+#define        M4U_PORT_CCU0                   MTK_M4U_ID(M4U_LARB7_ID, 0)
+#define        M4U_PORT_CCU1                   MTK_M4U_ID(M4U_LARB7_ID, 1)
+
+#endif
diff --git a/include/dt-bindings/regulator/active-semi,8865-regulator.h b/include/dt-bindings/regulator/active-semi,8865-regulator.h
new file mode 100644 (file)
index 0000000..15473db
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device Tree binding constants for the ACT8865 PMIC regulators
+ */
+
+#ifndef _DT_BINDINGS_REGULATOR_ACT8865_H
+#define _DT_BINDINGS_REGULATOR_ACT8865_H
+
+/*
+ * These constants should be used to specify regulator modes in device tree for
+ * ACT8865 regulators as follows:
+ * ACT8865_REGULATOR_MODE_FIXED:       It is specific to DCDC regulators and it
+ *                                     specifies the usage of fixed-frequency
+ *                                     PWM.
+ *
+ * ACT8865_REGULATOR_MODE_NORMAL:      It is specific to LDO regulators and it
+ *                                     specifies the usage of normal mode.
+ *
+ * ACT8865_REGULATOR_MODE_LOWPOWER:    For DCDC and LDO regulators; it specify
+ *                                     the usage of proprietary power-saving
+ *                                     mode.
+ */
+
+#define ACT8865_REGULATOR_MODE_FIXED           1
+#define ACT8865_REGULATOR_MODE_NORMAL          2
+#define ACT8865_REGULATOR_MODE_LOWPOWER        3
+
+#endif
index 9426b9a..0fecacc 100644 (file)
@@ -994,62 +994,11 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
 #endif
 #endif
 
-struct acpi_gpio_params {
-       unsigned int crs_entry_index;
-       unsigned int line_index;
-       bool active_low;
-};
-
-struct acpi_gpio_mapping {
-       const char *name;
-       const struct acpi_gpio_params *data;
-       unsigned int size;
-
-/* Ignore IoRestriction field */
-#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION      BIT(0)
-/*
- * When ACPI GPIO mapping table is in use the index parameter inside it
- * refers to the GPIO resource in _CRS method. That index has no
- * distinction of actual type of the resource. When consumer wants to
- * get GpioIo type explicitly, this quirk may be used.
- */
-#define ACPI_GPIO_QUIRK_ONLY_GPIOIO            BIT(1)
-
-       unsigned int quirks;
-};
-
 #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
-int acpi_dev_add_driver_gpios(struct acpi_device *adev,
-                             const struct acpi_gpio_mapping *gpios);
-
-static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
-{
-       if (adev)
-               adev->driver_gpios = NULL;
-}
-
-int devm_acpi_dev_add_driver_gpios(struct device *dev,
-                                  const struct acpi_gpio_mapping *gpios);
-void devm_acpi_dev_remove_driver_gpios(struct device *dev);
-
 bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                struct acpi_resource_gpio **agpio);
 int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
 #else
-static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
-                             const struct acpi_gpio_mapping *gpios)
-{
-       return -ENXIO;
-}
-static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
-
-static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
-                             const struct acpi_gpio_mapping *gpios)
-{
-       return -ENXIO;
-}
-static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
-
 static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                              struct acpi_resource_gpio **agpio)
 {
@@ -1302,11 +1251,16 @@ static inline int lpit_read_residency_count_address(u64 *address)
 #endif
 
 #ifdef CONFIG_ACPI_PPTT
+int acpi_pptt_cpu_is_thread(unsigned int cpu);
 int find_acpi_cpu_topology(unsigned int cpu, int level);
 int find_acpi_cpu_topology_package(unsigned int cpu);
 int find_acpi_cpu_topology_hetero_id(unsigned int cpu);
 int find_acpi_cpu_cache_topology(unsigned int cpu, int level);
 #else
+static inline int acpi_pptt_cpu_is_thread(unsigned int cpu)
+{
+       return -EINVAL;
+}
 static inline int find_acpi_cpu_topology(unsigned int cpu, int level)
 {
        return -EINVAL;
index 4a4d006..21e950e 100644 (file)
@@ -184,6 +184,9 @@ extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));
 extern int
 amd_iommu_update_ga(int cpu, bool is_run, void *data);
 
+extern int amd_iommu_activate_guest_mode(void *data);
+extern int amd_iommu_deactivate_guest_mode(void *data);
+
 #else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
 
 static inline int
@@ -198,6 +201,15 @@ amd_iommu_update_ga(int cpu, bool is_run, void *data)
        return 0;
 }
 
+static inline int amd_iommu_activate_guest_mode(void *data)
+{
+       return 0;
+}
+
+static inline int amd_iommu_deactivate_guest_mode(void *data)
+{
+       return 0;
+}
 #endif /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
 
 #endif /* _ASM_X86_AMD_IOMMU_H */
index 1cfe05e..42f2b51 100644 (file)
@@ -33,4 +33,30 @@ unsigned long topology_get_freq_scale(int cpu)
        return per_cpu(freq_scale, cpu);
 }
 
+struct cpu_topology {
+       int thread_id;
+       int core_id;
+       int package_id;
+       int llc_id;
+       cpumask_t thread_sibling;
+       cpumask_t core_sibling;
+       cpumask_t llc_sibling;
+};
+
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
+extern struct cpu_topology cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu)      (cpu_topology[cpu].package_id)
+#define topology_core_id(cpu)          (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
+#define topology_sibling_cpumask(cpu)  (&cpu_topology[cpu].thread_sibling)
+#define topology_llc_cpumask(cpu)      (&cpu_topology[cpu].llc_sibling)
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(int cpu);
+void update_siblings_masks(unsigned int cpu);
+void remove_cpu_topology(unsigned int cpuid);
+void reset_cpu_topology(void);
+#endif
+
 #endif /* _LINUX_ARCH_TOPOLOGY_H_ */
index 5e58bb2..11cdc7c 100644 (file)
@@ -30,7 +30,8 @@ static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b)
 
 static inline void ceph_buffer_put(struct ceph_buffer *b)
 {
-       kref_put(&b->kref, ceph_buffer_release);
+       if (b)
+               kref_put(&b->kref, ceph_buffer_release);
 }
 
 extern int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end);
index f0fd563..5e88e7e 100644 (file)
@@ -24,7 +24,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
                        long ______r;                                   \
                        static struct ftrace_likely_data                \
                                __aligned(4)                            \
-                               __section("_ftrace_annotated_branch")   \
+                               __section(_ftrace_annotated_branch)     \
                                ______f = {                             \
                                .data.func = __func__,                  \
                                .data.file = __FILE__,                  \
@@ -60,7 +60,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 #define __trace_if_value(cond) ({                      \
        static struct ftrace_branch_data                \
                __aligned(4)                            \
-               __section("_ftrace_branch")             \
+               __section(_ftrace_branch)               \
                __if_trace = {                          \
                        .func = __func__,               \
                        .file = __FILE__,               \
@@ -118,7 +118,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
        ".popsection\n\t"
 
 /* Annotate a C jump table to allow objtool to follow the code flow */
-#define __annotate_jump_table __section(".rodata..c_jump_table")
+#define __annotate_jump_table __section(.rodata..c_jump_table)
 
 #else
 #define annotate_reachable()
@@ -298,7 +298,7 @@ unsigned long read_word_at_a_time(const void *addr)
  * visible to the compiler.
  */
 #define __ADDRESSABLE(sym) \
-       static void * __section(".discard.addressable") __used \
+       static void * __section(.discard.addressable) __used \
                __PASTE(__addressable_##sym, __LINE__) = (void *)&sym;
 
 /**
index bb9a0db..12ae4b8 100644 (file)
@@ -256,7 +256,10 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
 {return 0;}
 #endif
 
-#define __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, is_retention) \
+#define __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter,                  \
+                               idx,                                    \
+                               state,                                  \
+                               is_retention)                           \
 ({                                                                     \
        int __ret = 0;                                                  \
                                                                        \
@@ -268,7 +271,7 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
        if (!is_retention)                                              \
                __ret =  cpu_pm_enter();                                \
        if (!__ret) {                                                   \
-               __ret = low_level_idle_enter(idx);                      \
+               __ret = low_level_idle_enter(state);                    \
                if (!is_retention)                                      \
                        cpu_pm_exit();                                  \
        }                                                               \
@@ -277,9 +280,15 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
 })
 
 #define CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx)       \
-       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, 0)
+       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, idx, 0)
 
 #define CPU_PM_CPU_IDLE_ENTER_RETENTION(low_level_idle_enter, idx)     \
-       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, 1)
+       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, idx, 1)
+
+#define CPU_PM_CPU_IDLE_ENTER_PARAM(low_level_idle_enter, idx, state)  \
+       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, state, 0)
+
+#define CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(low_level_idle_enter, idx, state)        \
+       __CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx, state, 1)
 
 #endif /* _LINUX_CPUIDLE_H */
index c05d4e6..03f8e98 100644 (file)
@@ -160,10 +160,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 static inline struct page *dma_alloc_contiguous(struct device *dev, size_t size,
                gfp_t gfp)
 {
-       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
-       size_t align = get_order(PAGE_ALIGN(size));
-
-       return alloc_pages_node(node, gfp, align);
+       return NULL;
 }
 
 static inline void dma_free_contiguous(struct device *dev, struct page *page,
index 3813211..0bff3d7 100644 (file)
@@ -42,13 +42,18 @@ void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
                dma_addr_t dma_addr, unsigned long attrs);
 long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
                dma_addr_t dma_addr);
-
-#ifdef CONFIG_ARCH_HAS_DMA_MMAP_PGPROT
 pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
                unsigned long attrs);
+
+#ifdef CONFIG_MMU
+pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs);
 #else
-# define arch_dma_mmap_pgprot(dev, prot, attrs)        pgprot_noncached(prot)
-#endif
+static inline pgprot_t dma_pgprot(struct device *dev, pgprot_t prot,
+               unsigned long attrs)
+{
+       return prot;    /* no protection bits supported without page tables */
+}
+#endif /* CONFIG_MMU */
 
 #ifdef CONFIG_DMA_NONCOHERENT_CACHE_SYNC
 void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
index 342dabd..c19483b 100644 (file)
@@ -440,7 +440,7 @@ struct dimm_info {
        char label[EDAC_MC_LABEL_LEN + 1];      /* DIMM label on motherboard */
 
        /* Memory location data */
-       unsigned location[EDAC_MAX_LAYERS];
+       unsigned int location[EDAC_MAX_LAYERS];
 
        struct mem_ctl_info *mci;       /* the parent */
 
@@ -451,7 +451,7 @@ struct dimm_info {
 
        u32 nr_pages;                   /* number of pages on this dimm */
 
-       unsigned csrow, cschannel;      /* Points to the old API data */
+       unsigned int csrow, cschannel;  /* Points to the old API data */
 
        u16 smbios_handle;              /* Handle for SMBIOS type 17 */
 };
@@ -597,7 +597,7 @@ struct mem_ctl_info {
                                           unsigned long page);
        int mc_idx;
        struct csrow_info **csrows;
-       unsigned nr_csrows, num_cschannel;
+       unsigned int nr_csrows, num_cschannel;
 
        /*
         * Memory Controller hierarchy
@@ -608,14 +608,14 @@ struct mem_ctl_info {
         * of the recent drivers enumerate memories per DIMM, instead.
         * When the memory controller is per rank, csbased is true.
         */
-       unsigned n_layers;
+       unsigned int n_layers;
        struct edac_mc_layer *layers;
        bool csbased;
 
        /*
         * DIMM info. Will eventually remove the entire csrows_info some day
         */
-       unsigned tot_dimms;
+       unsigned int tot_dimms;
        struct dimm_info **dimms;
 
        /*
index 280c61e..635a95c 100644 (file)
@@ -2,16 +2,16 @@
 #ifndef _LINUX_ERROR_INJECTION_H
 #define _LINUX_ERROR_INJECTION_H
 
-#ifdef CONFIG_FUNCTION_ERROR_INJECTION
+#include <linux/compiler.h>
+#include <asm-generic/error-injection.h>
 
-#include <asm/error-injection.h>
+#ifdef CONFIG_FUNCTION_ERROR_INJECTION
 
 extern bool within_error_injection_list(unsigned long addr);
 extern int get_injectable_error_type(unsigned long addr);
 
 #else /* !CONFIG_FUNCTION_ERROR_INJECTION */
 
-#include <asm-generic/error-injection.h>
 static inline bool within_error_injection_list(unsigned long addr)
 {
        return false;
index fb07b50..f338816 100644 (file)
@@ -510,22 +510,18 @@ alloc_pages(gfp_t gfp_mask, unsigned int order)
 }
 extern struct page *alloc_pages_vma(gfp_t gfp_mask, int order,
                        struct vm_area_struct *vma, unsigned long addr,
-                       int node, bool hugepage);
-#define alloc_hugepage_vma(gfp_mask, vma, addr, order) \
-       alloc_pages_vma(gfp_mask, order, vma, addr, numa_node_id(), true)
+                       int node);
 #else
 #define alloc_pages(gfp_mask, order) \
                alloc_pages_node(numa_node_id(), gfp_mask, order)
-#define alloc_pages_vma(gfp_mask, order, vma, addr, node, false)\
-       alloc_pages(gfp_mask, order)
-#define alloc_hugepage_vma(gfp_mask, vma, addr, order) \
+#define alloc_pages_vma(gfp_mask, order, vma, addr, node)\
        alloc_pages(gfp_mask, order)
 #endif
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
 #define alloc_page_vma(gfp_mask, vma, addr)                    \
-       alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id(), false)
+       alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id())
 #define alloc_page_vma_node(gfp_mask, vma, addr, node)         \
-       alloc_pages_vma(gfp_mask, 0, vma, addr, node, false)
+       alloc_pages_vma(gfp_mask, 0, vma, addr, node)
 
 extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
 extern unsigned long get_zeroed_page(gfp_t gfp_mask);
index 40915b4..2157717 100644 (file)
@@ -221,19 +221,6 @@ static inline int gpio_to_irq(unsigned gpio)
        return -EINVAL;
 }
 
-static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
-                                      unsigned int offset)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
-                                         unsigned int offset)
-{
-       WARN_ON(1);
-}
-
 static inline int irq_to_gpio(unsigned irq)
 {
        /* irq can never have been returned from gpio_to_irq() */
@@ -241,30 +228,6 @@ static inline int irq_to_gpio(unsigned irq)
        return -EINVAL;
 }
 
-static inline int
-gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
-                      unsigned int gpio_offset, unsigned int pin_offset,
-                      unsigned int npins)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline int
-gpiochip_add_pingroup_range(struct gpio_chip *chip,
-                       struct pinctrl_dev *pctldev,
-                       unsigned int gpio_offset, const char *pin_group)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline void
-gpiochip_remove_pin_ranges(struct gpio_chip *chip)
-{
-       WARN_ON(1);
-}
-
 static inline int devm_gpio_request(struct device *dev, unsigned gpio,
                                    const char *label)
 {
index a7f08fb..b70af92 100644 (file)
@@ -170,18 +170,8 @@ struct gpio_desc *gpio_to_desc(unsigned gpio);
 int desc_to_gpio(const struct gpio_desc *desc);
 
 /* Child properties interface */
-struct device_node;
 struct fwnode_handle;
 
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label);
-struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
-                                             struct device_node *node,
-                                             const char *propname, int index,
-                                             enum gpiod_flags dflags,
-                                             const char *label);
 struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         const char *propname, int index,
                                         enum gpiod_flags dflags,
@@ -530,28 +520,8 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
 }
 
 /* Child properties interface */
-struct device_node;
 struct fwnode_handle;
 
-static inline
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label)
-{
-       return ERR_PTR(-ENOSYS);
-}
-
-static inline
-struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
-                                             struct device_node *node,
-                                             const char *propname, int index,
-                                             enum gpiod_flags dflags,
-                                             const char *label)
-{
-       return ERR_PTR(-ENOSYS);
-}
-
 static inline
 struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         const char *propname, int index,
@@ -584,6 +554,111 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
                                                      flags, label);
 }
 
+#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
+struct device_node;
+
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label);
+
+#else  /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
+
+struct device_node;
+
+static inline
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+#endif /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
+
+#ifdef CONFIG_GPIOLIB
+struct device_node;
+
+struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
+                                             struct device_node *node,
+                                             const char *propname, int index,
+                                             enum gpiod_flags dflags,
+                                             const char *label);
+
+#else  /* CONFIG_GPIOLIB */
+
+struct device_node;
+
+static inline
+struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
+                                             struct device_node *node,
+                                             const char *propname, int index,
+                                             enum gpiod_flags dflags,
+                                             const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+struct acpi_gpio_params {
+       unsigned int crs_entry_index;
+       unsigned int line_index;
+       bool active_low;
+};
+
+struct acpi_gpio_mapping {
+       const char *name;
+       const struct acpi_gpio_params *data;
+       unsigned int size;
+
+/* Ignore IoRestriction field */
+#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION      BIT(0)
+/*
+ * When ACPI GPIO mapping table is in use the index parameter inside it
+ * refers to the GPIO resource in _CRS method. That index has no
+ * distinction of actual type of the resource. When consumer wants to
+ * get GpioIo type explicitly, this quirk may be used.
+ */
+#define ACPI_GPIO_QUIRK_ONLY_GPIOIO            BIT(1)
+
+       unsigned int quirks;
+};
+
+#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI)
+
+struct acpi_device;
+
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios);
+void acpi_dev_remove_driver_gpios(struct acpi_device *adev);
+
+int devm_acpi_dev_add_driver_gpios(struct device *dev,
+                                  const struct acpi_gpio_mapping *gpios);
+void devm_acpi_dev_remove_driver_gpios(struct device *dev);
+
+#else  /* CONFIG_GPIOLIB && CONFIG_ACPI */
+
+struct acpi_device;
+
+static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios)
+{
+       return -ENXIO;
+}
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
+
+static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
+                             const struct acpi_gpio_mapping *gpios)
+{
+       return -ENXIO;
+}
+static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
+
+#endif /* CONFIG_GPIOLIB && CONFIG_ACPI */
+
+
 #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
 
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
index 6a0e420..f8245d6 100644 (file)
@@ -20,9 +20,8 @@ struct module;
 enum gpiod_flags;
 enum gpio_lookup_flags;
 
-#ifdef CONFIG_GPIOLIB
+struct gpio_chip;
 
-#ifdef CONFIG_GPIOLIB_IRQCHIP
 /**
  * struct gpio_irq_chip - GPIO interrupt controller
  */
@@ -49,6 +48,84 @@ struct gpio_irq_chip {
         */
        const struct irq_domain_ops *domain_ops;
 
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       /**
+        * @fwnode:
+        *
+        * Firmware node corresponding to this gpiochip/irqchip, necessary
+        * for hierarchical irqdomain support.
+        */
+       struct fwnode_handle *fwnode;
+
+       /**
+        * @parent_domain:
+        *
+        * If non-NULL, will be set as the parent of this GPIO interrupt
+        * controller's IRQ domain to establish a hierarchical interrupt
+        * domain. The presence of this will activate the hierarchical
+        * interrupt support.
+        */
+       struct irq_domain *parent_domain;
+
+       /**
+        * @child_to_parent_hwirq:
+        *
+        * This callback translates a child hardware IRQ offset to a parent
+        * hardware IRQ offset on a hierarchical interrupt chip. The child
+        * hardware IRQs correspond to the GPIO index 0..ngpio-1 (see the
+        * ngpio field of struct gpio_chip) and the corresponding parent
+        * hardware IRQ and type (such as IRQ_TYPE_*) shall be returned by
+        * the driver. The driver can calculate this from an offset or using
+        * a lookup table or whatever method is best for this chip. Return
+        * 0 on successful translation in the driver.
+        *
+        * If some ranges of hardware IRQs do not have a corresponding parent
+        * HWIRQ, return -EINVAL, but also make sure to fill in @valid_mask and
+        * @need_valid_mask to make these GPIO lines unavailable for
+        * translation.
+        */
+       int (*child_to_parent_hwirq)(struct gpio_chip *chip,
+                                    unsigned int child_hwirq,
+                                    unsigned int child_type,
+                                    unsigned int *parent_hwirq,
+                                    unsigned int *parent_type);
+
+       /**
+        * @populate_parent_fwspec:
+        *
+        * This optional callback populates the &struct irq_fwspec for the
+        * parent's IRQ domain. If this is not specified, then
+        * &gpiochip_populate_parent_fwspec_twocell will be used. A four-cell
+        * variant named &gpiochip_populate_parent_fwspec_fourcell is also
+        * available.
+        */
+       void (*populate_parent_fwspec)(struct gpio_chip *chip,
+                                      struct irq_fwspec *fwspec,
+                                      unsigned int parent_hwirq,
+                                      unsigned int parent_type);
+
+       /**
+        * @child_offset_to_irq:
+        *
+        * This optional callback is used to translate the child's GPIO line
+        * offset on the GPIO chip to an IRQ number for the GPIO to_irq()
+        * callback. If this is not specified, then a default callback will be
+        * provided that returns the line offset.
+        */
+       unsigned int (*child_offset_to_irq)(struct gpio_chip *chip,
+                                           unsigned int pin);
+
+       /**
+        * @child_irq_domain_ops:
+        *
+        * The IRQ domain operations that will be used for this GPIO IRQ
+        * chip. If no operations are provided, then default callbacks will
+        * be populated to setup the IRQ hierarchy. Some drivers need to
+        * supply their own translate function.
+        */
+       struct irq_domain_ops child_irq_domain_ops;
+#endif
+
        /**
         * @handler:
         *
@@ -125,11 +202,17 @@ struct gpio_irq_chip {
        bool threaded;
 
        /**
-        * @need_valid_mask:
-        *
-        * If set core allocates @valid_mask with all bits set to one.
+        * @init_valid_mask: optional routine to initialize @valid_mask, to be
+        * used if not all GPIO lines are valid interrupts. Sometimes some
+        * lines just cannot fire interrupts, and this routine, when defined,
+        * is passed a bitmap in "valid_mask" and it will have ngpios
+        * bits from 0..(ngpios-1) set to "1" as in valid. The callback can
+        * then directly set some bits to "0" if they cannot be used for
+        * interrupts.
         */
-       bool need_valid_mask;
+       void (*init_valid_mask)(struct gpio_chip *chip,
+                               unsigned long *valid_mask,
+                               unsigned int ngpios);
 
        /**
         * @valid_mask:
@@ -161,7 +244,6 @@ struct gpio_irq_chip {
         */
        void            (*irq_disable)(struct irq_data *data);
 };
-#endif /* CONFIG_GPIOLIB_IRQCHIP */
 
 /**
  * struct gpio_chip - abstract a GPIO controller
@@ -282,7 +364,9 @@ struct gpio_chip {
        void                    (*dbg_show)(struct seq_file *s,
                                                struct gpio_chip *chip);
 
-       int                     (*init_valid_mask)(struct gpio_chip *chip);
+       int                     (*init_valid_mask)(struct gpio_chip *chip,
+                                                  unsigned long *valid_mask,
+                                                  unsigned int ngpios);
 
        int                     base;
        u16                     ngpio;
@@ -320,15 +404,6 @@ struct gpio_chip {
        struct gpio_irq_chip irq;
 #endif /* CONFIG_GPIOLIB_IRQCHIP */
 
-       /**
-        * @need_valid_mask:
-        *
-        * If set core allocates @valid_mask with all its values initialized
-        * with init_valid_mask() or set to one if init_valid_mask() is not
-        * defined
-        */
-       bool need_valid_mask;
-
        /**
         * @valid_mask:
         *
@@ -421,9 +496,6 @@ extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
 extern struct gpio_chip *gpiochip_find(void *data,
                              int (*match)(struct gpio_chip *chip, void *data));
 
-/* lock/unlock as IRQ */
-int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
-void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
 bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
 int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset);
 void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset);
@@ -441,15 +513,40 @@ bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);
 /* get driver data */
 void *gpiochip_get_data(struct gpio_chip *chip);
 
-struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
-
 struct bgpio_pdata {
        const char *label;
        int base;
        int ngpio;
 };
 
-#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+
+void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                            struct irq_fwspec *fwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type);
+void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                             struct irq_fwspec *fwspec,
+                                             unsigned int parent_hwirq,
+                                             unsigned int parent_type);
+
+#else
+
+static inline void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                                   struct irq_fwspec *fwspec,
+                                                   unsigned int parent_hwirq,
+                                                   unsigned int parent_type)
+{
+}
+
+static inline void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                                    struct irq_fwspec *fwspec,
+                                                    unsigned int parent_hwirq,
+                                                    unsigned int parent_type)
+{
+}
+
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
 int bgpio_init(struct gpio_chip *gc, struct device *dev,
               unsigned long sz, void __iomem *dat, void __iomem *set,
@@ -463,10 +560,6 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 #define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
 #define BGPIOF_NO_OUTPUT               BIT(5) /* only input */
 
-#endif /* CONFIG_GPIO_GENERIC */
-
-#ifdef CONFIG_GPIOLIB_IRQCHIP
-
 int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq);
 void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
@@ -555,15 +648,11 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
 }
 #endif /* CONFIG_LOCKDEP */
 
-#endif /* CONFIG_GPIOLIB_IRQCHIP */
-
 int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
 void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
 int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
                            unsigned long config);
 
-#ifdef CONFIG_PINCTRL
-
 /**
  * struct gpio_pin_range - pin range controlled by a gpio chip
  * @node: list for maintaining set of pin ranges, used internally
@@ -576,6 +665,8 @@ struct gpio_pin_range {
        struct pinctrl_gpio_range range;
 };
 
+#ifdef CONFIG_PINCTRL
+
 int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                           unsigned int gpio_offset, unsigned int pin_offset,
                           unsigned int npins);
@@ -586,8 +677,6 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
 
 #else /* ! CONFIG_PINCTRL */
 
-struct pinctrl_dev;
-
 static inline int
 gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                       unsigned int gpio_offset, unsigned int pin_offset,
@@ -619,6 +708,15 @@ void gpiochip_free_own_desc(struct gpio_desc *desc);
 void devprop_gpiochip_set_names(struct gpio_chip *chip,
                                const struct fwnode_handle *fwnode);
 
+#ifdef CONFIG_GPIOLIB
+
+/* lock/unlock as IRQ */
+int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
+void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
+
+
+struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
+
 #else /* CONFIG_GPIOLIB */
 
 static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
@@ -628,6 +726,18 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
        return ERR_PTR(-ENODEV);
 }
 
+static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
+                                         unsigned int offset)
+{
+       WARN_ON(1);
+}
 #endif /* CONFIG_GPIOLIB */
 
-#endif
+#endif /* __LINUX_GPIO_DRIVER_H */
index 5ecb055..de102e4 100644 (file)
@@ -188,6 +188,10 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv)
 struct device *i3cdev_to_dev(struct i3c_device *i3cdev);
 struct i3c_device *dev_to_i3cdev(struct device *dev);
 
+const struct i3c_device_id *
+i3c_device_match_id(struct i3c_device *i3cdev,
+                   const struct i3c_device_id *id_table);
+
 static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev,
                                      void *data)
 {
index 1f08fa8..9cb39d9 100644 (file)
@@ -71,6 +71,9 @@ struct i2c_dev_boardinfo {
  * @common: common part of the I2C device descriptor
  * @boardinfo: pointer to the boardinfo attached to this I2C device
  * @dev: I2C device object registered to the I2C framework
+ * @addr: I2C device address
+ * @lvr: LVR (Legacy Virtual Register) needed by the I3C core to know about
+ *      the I2C device limitations
  *
  * Each I2C device connected on the bus will have an i2c_dev_desc.
  * This object is created by the core and later attached to the controller
@@ -84,6 +87,8 @@ struct i2c_dev_desc {
        struct i3c_i2c_dev_desc common;
        const struct i2c_dev_boardinfo *boardinfo;
        struct i2c_client *dev;
+       u16 addr;
+       u8 lvr;
 };
 
 /**
index ceabb01..1ecb6b4 100644 (file)
@@ -48,7 +48,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
        { "ELAN0618", 0 },
        { "ELAN0619", 0 },
        { "ELAN061A", 0 },
-       { "ELAN061B", 0 },
+/*     { "ELAN061B", 0 }, not working on the Lenovo Legion Y7000 */
        { "ELAN061C", 0 },
        { "ELAN061D", 0 },
        { "ELAN061E", 0 },
index f2ae8a0..ed11ef5 100644 (file)
 #define dma_frcd_type(d) ((d >> 30) & 1)
 #define dma_frcd_fault_reason(c) (c & 0xff)
 #define dma_frcd_source_id(c) (c & 0xffff)
+#define dma_frcd_pasid_value(c) (((c) >> 8) & 0xfffff)
+#define dma_frcd_pasid_present(c) (((c) >> 31) & 1)
 /* low 64 bit */
 #define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
 
@@ -346,7 +348,6 @@ enum {
 #define QI_PC_PASID_SEL                (QI_PC_TYPE | QI_PC_GRAN(1))
 
 #define QI_EIOTLB_ADDR(addr)   ((u64)(addr) & VTD_PAGE_MASK)
-#define QI_EIOTLB_GL(gl)       (((u64)gl) << 7)
 #define QI_EIOTLB_IH(ih)       (((u64)ih) << 6)
 #define QI_EIOTLB_AM(am)       (((u64)am))
 #define QI_EIOTLB_PASID(pasid)         (((u64)pasid) << 32)
@@ -378,8 +379,6 @@ enum {
 #define QI_RESP_INVALID                0x1
 #define QI_RESP_FAILURE                0xf
 
-#define QI_GRAN_ALL_ALL                        0
-#define QI_GRAN_NONG_ALL               1
 #define QI_GRAN_NONG_PASID             2
 #define QI_GRAN_PSI_PASID              3
 
index b5a450a..ec7a134 100644 (file)
@@ -1,7 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef __IO_PGTABLE_H
 #define __IO_PGTABLE_H
+
 #include <linux/bitops.h>
+#include <linux/iommu.h>
 
 /*
  * Public API for use by IOMMU drivers
@@ -17,22 +19,31 @@ enum io_pgtable_fmt {
 };
 
 /**
- * struct iommu_gather_ops - IOMMU callbacks for TLB and page table management.
+ * struct iommu_flush_ops - IOMMU callbacks for TLB and page table management.
  *
- * @tlb_flush_all: Synchronously invalidate the entire TLB context.
- * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range.
- * @tlb_sync:      Ensure any queued TLB invalidation has taken effect, and
- *                 any corresponding page table updates are visible to the
- *                 IOMMU.
+ * @tlb_flush_all:  Synchronously invalidate the entire TLB context.
+ * @tlb_flush_walk: Synchronously invalidate all intermediate TLB state
+ *                  (sometimes referred to as the "walk cache") for a virtual
+ *                  address range.
+ * @tlb_flush_leaf: Synchronously invalidate all leaf TLB state for a virtual
+ *                  address range.
+ * @tlb_add_page:   Optional callback to queue up leaf TLB invalidation for a
+ *                  single page.  IOMMUs that cannot batch TLB invalidation
+ *                  operations efficiently will typically issue them here, but
+ *                  others may decide to update the iommu_iotlb_gather structure
+ *                  and defer the invalidation until iommu_tlb_sync() instead.
  *
  * Note that these can all be called in atomic context and must therefore
  * not block.
  */
-struct iommu_gather_ops {
+struct iommu_flush_ops {
        void (*tlb_flush_all)(void *cookie);
-       void (*tlb_add_flush)(unsigned long iova, size_t size, size_t granule,
-                             bool leaf, void *cookie);
-       void (*tlb_sync)(void *cookie);
+       void (*tlb_flush_walk)(unsigned long iova, size_t size, size_t granule,
+                              void *cookie);
+       void (*tlb_flush_leaf)(unsigned long iova, size_t size, size_t granule,
+                              void *cookie);
+       void (*tlb_add_page)(struct iommu_iotlb_gather *gather,
+                            unsigned long iova, size_t granule, void *cookie);
 };
 
 /**
@@ -65,10 +76,9 @@ struct io_pgtable_cfg {
         *      (unmapped) entries but the hardware might do so anyway, perform
         *      TLB maintenance when mapping as well as when unmapping.
         *
-        * IO_PGTABLE_QUIRK_ARM_MTK_4GB: (ARM v7s format) Set bit 9 in all
-        *      PTEs, for Mediatek IOMMUs which treat it as a 33rd address bit
-        *      when the SoC is in "4GB mode" and they can only access the high
-        *      remap of DRAM (0x1_00000000 to 0x1_ffffffff).
+        * IO_PGTABLE_QUIRK_ARM_MTK_EXT: (ARM v7s format) MediaTek IOMMUs extend
+        *      to support up to 34 bits PA where the bit32 and bit33 are
+        *      encoded in the bit9 and bit4 of the PTE respectively.
         *
         * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs
         *      on unmap, for DMA domains using the flush queue mechanism for
@@ -77,14 +87,14 @@ struct io_pgtable_cfg {
        #define IO_PGTABLE_QUIRK_ARM_NS         BIT(0)
        #define IO_PGTABLE_QUIRK_NO_PERMS       BIT(1)
        #define IO_PGTABLE_QUIRK_TLBI_ON_MAP    BIT(2)
-       #define IO_PGTABLE_QUIRK_ARM_MTK_4GB    BIT(3)
+       #define IO_PGTABLE_QUIRK_ARM_MTK_EXT    BIT(3)
        #define IO_PGTABLE_QUIRK_NON_STRICT     BIT(4)
        unsigned long                   quirks;
        unsigned long                   pgsize_bitmap;
        unsigned int                    ias;
        unsigned int                    oas;
        bool                            coherent_walk;
-       const struct iommu_gather_ops   *tlb;
+       const struct iommu_flush_ops    *tlb;
        struct device                   *iommu_dev;
 
        /* Low-level data specific to the table format */
@@ -128,7 +138,7 @@ struct io_pgtable_ops {
        int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
                   phys_addr_t paddr, size_t size, int prot);
        size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
-                       size_t size);
+                       size_t size, struct iommu_iotlb_gather *gather);
        phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
                                    unsigned long iova);
 };
@@ -184,15 +194,27 @@ static inline void io_pgtable_tlb_flush_all(struct io_pgtable *iop)
        iop->cfg.tlb->tlb_flush_all(iop->cookie);
 }
 
-static inline void io_pgtable_tlb_add_flush(struct io_pgtable *iop,
-               unsigned long iova, size_t size, size_t granule, bool leaf)
+static inline void
+io_pgtable_tlb_flush_walk(struct io_pgtable *iop, unsigned long iova,
+                         size_t size, size_t granule)
+{
+       iop->cfg.tlb->tlb_flush_walk(iova, size, granule, iop->cookie);
+}
+
+static inline void
+io_pgtable_tlb_flush_leaf(struct io_pgtable *iop, unsigned long iova,
+                         size_t size, size_t granule)
 {
-       iop->cfg.tlb->tlb_add_flush(iova, size, granule, leaf, iop->cookie);
+       iop->cfg.tlb->tlb_flush_leaf(iova, size, granule, iop->cookie);
 }
 
-static inline void io_pgtable_tlb_sync(struct io_pgtable *iop)
+static inline void
+io_pgtable_tlb_add_page(struct io_pgtable *iop,
+                       struct iommu_iotlb_gather * gather, unsigned long iova,
+                       size_t granule)
 {
-       iop->cfg.tlb->tlb_sync(iop->cookie);
+       if (iop->cfg.tlb->tlb_add_page)
+               iop->cfg.tlb->tlb_add_page(gather, iova, granule, iop->cookie);
 }
 
 /**
diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h
deleted file mode 100644 (file)
index 51e2b9f..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-#ifndef _LINUX_IOC4_H
-#define _LINUX_IOC4_H
-
-#include <linux/interrupt.h>
-
-/***************
- * Definitions *
- ***************/
-
-/* Miscellaneous values inherent to hardware */
-
-#define IOC4_EXTINT_COUNT_DIVISOR 520  /* PCI clocks per COUNT tick */
-
-/***********************************
- * Structures needed by subdrivers *
- ***********************************/
-
-/* This structure fully describes the IOC4 miscellaneous registers which
- * appear at bar[0]+0x00000 through bar[0]+0x0005c.  The corresponding
- * PCI resource is managed by the main IOC4 driver because it contains
- * registers of interest to many different IOC4 subdrivers.
- */
-struct ioc4_misc_regs {
-       /* Miscellaneous IOC4 registers */
-       union ioc4_pci_err_addr_l {
-               uint32_t raw;
-               struct {
-                       uint32_t valid:1;       /* Address captured */
-                       uint32_t master_id:4;   /* Unit causing error
-                                                * 0/1: Serial port 0 TX/RX
-                                                * 2/3: Serial port 1 TX/RX
-                                                * 4/5: Serial port 2 TX/RX
-                                                * 6/7: Serial port 3 TX/RX
-                                                * 8: ATA/ATAPI
-                                                * 9-15: Undefined
-                                                */
-                       uint32_t mul_err:1;     /* Multiple errors occurred */
-                       uint32_t addr:26;       /* Bits 31-6 of error addr */
-               } fields;
-       } pci_err_addr_l;
-       uint32_t pci_err_addr_h;        /* Bits 63-32 of error addr */
-       union ioc4_sio_int {
-               uint32_t raw;
-               struct {
-                       uint8_t tx_mt:1;        /* TX ring buffer empty */
-                       uint8_t rx_full:1;      /* RX ring buffer full */
-                       uint8_t rx_high:1;      /* RX high-water exceeded */
-                       uint8_t rx_timer:1;     /* RX timer has triggered */
-                       uint8_t delta_dcd:1;    /* DELTA_DCD seen */
-                       uint8_t delta_cts:1;    /* DELTA_CTS seen */
-                       uint8_t intr_pass:1;    /* Interrupt pass-through */
-                       uint8_t tx_explicit:1;  /* TX, MCW, or delay complete */
-               } fields[4];
-       } sio_ir;               /* Serial interrupt state */
-       union ioc4_other_int {
-               uint32_t raw;
-               struct {
-                       uint32_t ata_int:1;     /* ATA port passthru */
-                       uint32_t ata_memerr:1;  /* ATA halted by mem error */
-                       uint32_t memerr:4;      /* Serial halted by mem err */
-                       uint32_t kbd_int:1;     /* kbd/mouse intr asserted */
-                       uint32_t reserved:16;   /* zero */
-                       uint32_t rt_int:1;      /* INT_OUT section latch */
-                       uint32_t gen_int:8;     /* Intr. from generic pins */
-               } fields;
-       } other_ir;             /* Other interrupt state */
-       union ioc4_sio_int sio_ies;     /* Serial interrupt enable set */
-       union ioc4_other_int other_ies; /* Other interrupt enable set */
-       union ioc4_sio_int sio_iec;     /* Serial interrupt enable clear */
-       union ioc4_other_int other_iec; /* Other interrupt enable clear */
-       union ioc4_sio_cr {
-               uint32_t raw;
-               struct {
-                       uint32_t cmd_pulse:4;   /* Bytebus strobe width */
-                       uint32_t arb_diag:3;    /* PCI bus requester */
-                       uint32_t sio_diag_idle:1;       /* Active ser req? */
-                       uint32_t ata_diag_idle:1;       /* Active ATA req? */
-                       uint32_t ata_diag_active:1;     /* ATA req is winner */
-                       uint32_t reserved:22;   /* zero */
-               } fields;
-       } sio_cr;
-       uint32_t unused1;
-       union ioc4_int_out {
-               uint32_t raw;
-               struct {
-                       uint32_t count:16;      /* Period control */
-                       uint32_t mode:3;        /* Output signal shape */
-                       uint32_t reserved:11;   /* zero */
-                       uint32_t diag:1;        /* Timebase control */
-                       uint32_t int_out:1;     /* Current value */
-               } fields;
-       } int_out;              /* External interrupt output control */
-       uint32_t unused2;
-       union ioc4_gpcr {
-               uint32_t raw;
-               struct {
-                       uint32_t dir:8; /* Pin direction */
-                       uint32_t edge:8;        /* Edge/level mode */
-                       uint32_t reserved1:4;   /* zero */
-                       uint32_t int_out_en:1;  /* INT_OUT enable */
-                       uint32_t reserved2:11;  /* zero */
-               } fields;
-       } gpcr_s;               /* Generic PIO control set */
-       union ioc4_gpcr gpcr_c; /* Generic PIO control clear */
-       union ioc4_gpdr {
-               uint32_t raw;
-               struct {
-                       uint32_t gen_pin:8;     /* State of pins */
-                       uint32_t reserved:24;
-               } fields;
-       } gpdr;                 /* Generic PIO data */
-       uint32_t unused3;
-       union ioc4_gppr {
-               uint32_t raw;
-               struct {
-                       uint32_t gen_pin:1;     /* Single pin state */
-                       uint32_t reserved:31;
-               } fields;
-       } gppr[8];              /* Generic PIO pins */
-};
-
-/* Masks for GPCR DIR pins */
-#define IOC4_GPCR_DIR_0 0x01   /* External interrupt output */
-#define IOC4_GPCR_DIR_1 0x02   /* External interrupt input */
-#define IOC4_GPCR_DIR_2 0x04
-#define IOC4_GPCR_DIR_3 0x08   /* Keyboard/mouse presence */
-#define IOC4_GPCR_DIR_4 0x10   /* Ser. port 0 xcvr select (0=232, 1=422) */
-#define IOC4_GPCR_DIR_5 0x20   /* Ser. port 1 xcvr select (0=232, 1=422) */
-#define IOC4_GPCR_DIR_6 0x40   /* Ser. port 2 xcvr select (0=232, 1=422) */
-#define IOC4_GPCR_DIR_7 0x80   /* Ser. port 3 xcvr select (0=232, 1=422) */
-
-/* Masks for GPCR EDGE pins */
-#define IOC4_GPCR_EDGE_0 0x01
-#define IOC4_GPCR_EDGE_1 0x02  /* External interrupt input */
-#define IOC4_GPCR_EDGE_2 0x04
-#define IOC4_GPCR_EDGE_3 0x08
-#define IOC4_GPCR_EDGE_4 0x10
-#define IOC4_GPCR_EDGE_5 0x20
-#define IOC4_GPCR_EDGE_6 0x40
-#define IOC4_GPCR_EDGE_7 0x80
-
-#define IOC4_VARIANT_IO9       0x0900
-#define IOC4_VARIANT_PCI_RT    0x0901
-#define IOC4_VARIANT_IO10      0x1000
-
-/* One of these per IOC4 */
-struct ioc4_driver_data {
-       struct list_head idd_list;
-       unsigned long idd_bar0;
-       struct pci_dev *idd_pdev;
-       const struct pci_device_id *idd_pci_id;
-       struct ioc4_misc_regs __iomem *idd_misc_regs;
-       unsigned long count_period;
-       void *idd_serial_data;
-       unsigned int idd_variant;
-};
-
-/* One per submodule */
-struct ioc4_submodule {
-       struct list_head is_list;
-       char *is_name;
-       struct module *is_owner;
-       int (*is_probe) (struct ioc4_driver_data *);
-       int (*is_remove) (struct ioc4_driver_data *);
-};
-
-#define IOC4_NUM_CARDS         8       /* max cards per partition */
-
-/**********************************
- * Functions needed by submodules *
- **********************************/
-
-extern int ioc4_register_submodule(struct ioc4_submodule *);
-extern void ioc4_unregister_submodule(struct ioc4_submodule *);
-
-#endif                         /* _LINUX_IOC4_H */
index fdc355c..29bac53 100644 (file)
@@ -191,6 +191,23 @@ struct iommu_sva_ops {
 
 #ifdef CONFIG_IOMMU_API
 
+/**
+ * struct iommu_iotlb_gather - Range information for a pending IOTLB flush
+ *
+ * @start: IOVA representing the start of the range to be flushed
+ * @end: IOVA representing the end of the range to be flushed (exclusive)
+ * @pgsize: The interval at which to perform the flush
+ *
+ * This structure is intended to be updated by multiple calls to the
+ * ->unmap() function in struct iommu_ops before eventually being passed
+ * into ->iotlb_sync().
+ */
+struct iommu_iotlb_gather {
+       unsigned long           start;
+       unsigned long           end;
+       size_t                  pgsize;
+};
+
 /**
  * struct iommu_ops - iommu ops and capabilities
  * @capable: check capability
@@ -201,7 +218,6 @@ struct iommu_sva_ops {
  * @map: map a physically contiguous memory region to an iommu domain
  * @unmap: unmap a physically contiguous memory region from an iommu domain
  * @flush_iotlb_all: Synchronously flush all hardware TLBs for this domain
- * @iotlb_range_add: Add a given iova range to the flush queue for this domain
  * @iotlb_sync_map: Sync mappings created recently using @map to the hardware
  * @iotlb_sync: Flush all queued ranges from the hardware TLBs and empty flush
  *            queue
@@ -242,12 +258,11 @@ struct iommu_ops {
        int (*map)(struct iommu_domain *domain, unsigned long iova,
                   phys_addr_t paddr, size_t size, int prot);
        size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
-                    size_t size);
+                    size_t size, struct iommu_iotlb_gather *iotlb_gather);
        void (*flush_iotlb_all)(struct iommu_domain *domain);
-       void (*iotlb_range_add)(struct iommu_domain *domain,
-                               unsigned long iova, size_t size);
        void (*iotlb_sync_map)(struct iommu_domain *domain);
-       void (*iotlb_sync)(struct iommu_domain *domain);
+       void (*iotlb_sync)(struct iommu_domain *domain,
+                          struct iommu_iotlb_gather *iotlb_gather);
        phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
        int (*add_device)(struct device *dev);
        void (*remove_device)(struct device *dev);
@@ -378,6 +393,13 @@ static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
        return (struct iommu_device *)dev_get_drvdata(dev);
 }
 
+static inline void iommu_iotlb_gather_init(struct iommu_iotlb_gather *gather)
+{
+       *gather = (struct iommu_iotlb_gather) {
+               .start  = ULONG_MAX,
+       };
+}
+
 #define IOMMU_GROUP_NOTIFY_ADD_DEVICE          1 /* Device added */
 #define IOMMU_GROUP_NOTIFY_DEL_DEVICE          2 /* Pre Device removed */
 #define IOMMU_GROUP_NOTIFY_BIND_DRIVER         3 /* Pre Driver bind */
@@ -402,7 +424,8 @@ extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
 extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
                          size_t size);
 extern size_t iommu_unmap_fast(struct iommu_domain *domain,
-                              unsigned long iova, size_t size);
+                              unsigned long iova, size_t size,
+                              struct iommu_iotlb_gather *iotlb_gather);
 extern size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
                           struct scatterlist *sg,unsigned int nents, int prot);
 extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova);
@@ -413,6 +436,9 @@ extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
 extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
 extern int iommu_request_dm_for_dev(struct device *dev);
 extern int iommu_request_dma_domain_for_dev(struct device *dev);
+extern void iommu_set_default_passthrough(bool cmd_line);
+extern void iommu_set_default_translated(bool cmd_line);
+extern bool iommu_default_passthrough(void);
 extern struct iommu_resv_region *
 iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot,
                        enum iommu_resv_type type);
@@ -476,17 +502,38 @@ static inline void iommu_flush_tlb_all(struct iommu_domain *domain)
                domain->ops->flush_iotlb_all(domain);
 }
 
-static inline void iommu_tlb_range_add(struct iommu_domain *domain,
-                                      unsigned long iova, size_t size)
+static inline void iommu_tlb_sync(struct iommu_domain *domain,
+                                 struct iommu_iotlb_gather *iotlb_gather)
 {
-       if (domain->ops->iotlb_range_add)
-               domain->ops->iotlb_range_add(domain, iova, size);
+       if (domain->ops->iotlb_sync)
+               domain->ops->iotlb_sync(domain, iotlb_gather);
+
+       iommu_iotlb_gather_init(iotlb_gather);
 }
 
-static inline void iommu_tlb_sync(struct iommu_domain *domain)
+static inline void iommu_iotlb_gather_add_page(struct iommu_domain *domain,
+                                              struct iommu_iotlb_gather *gather,
+                                              unsigned long iova, size_t size)
 {
-       if (domain->ops->iotlb_sync)
-               domain->ops->iotlb_sync(domain);
+       unsigned long start = iova, end = start + size;
+
+       /*
+        * If the new page is disjoint from the current range or is mapped at
+        * a different granularity, then sync the TLB so that the gather
+        * structure can be rewritten.
+        */
+       if (gather->pgsize != size ||
+           end < gather->start || start > gather->end) {
+               if (gather->pgsize)
+                       iommu_tlb_sync(domain, gather);
+               gather->pgsize = size;
+       }
+
+       if (gather->end < end)
+               gather->end = end;
+
+       if (gather->start > start)
+               gather->start = start;
 }
 
 /* PCI device grouping function */
@@ -567,6 +614,7 @@ struct iommu_group {};
 struct iommu_fwspec {};
 struct iommu_device {};
 struct iommu_fault_param {};
+struct iommu_iotlb_gather {};
 
 static inline bool iommu_present(struct bus_type *bus)
 {
@@ -621,7 +669,8 @@ static inline size_t iommu_unmap(struct iommu_domain *domain,
 }
 
 static inline size_t iommu_unmap_fast(struct iommu_domain *domain,
-                                     unsigned long iova, int gfp_order)
+                                     unsigned long iova, int gfp_order,
+                                     struct iommu_iotlb_gather *iotlb_gather)
 {
        return 0;
 }
@@ -637,12 +686,8 @@ static inline void iommu_flush_tlb_all(struct iommu_domain *domain)
 {
 }
 
-static inline void iommu_tlb_range_add(struct iommu_domain *domain,
-                                      unsigned long iova, size_t size)
-{
-}
-
-static inline void iommu_tlb_sync(struct iommu_domain *domain)
+static inline void iommu_tlb_sync(struct iommu_domain *domain,
+                                 struct iommu_iotlb_gather *iotlb_gather)
 {
 }
 
@@ -694,6 +739,19 @@ static inline int iommu_request_dma_domain_for_dev(struct device *dev)
        return -ENODEV;
 }
 
+static inline void iommu_set_default_passthrough(bool cmd_line)
+{
+}
+
+static inline void iommu_set_default_translated(bool cmd_line)
+{
+}
+
+static inline bool iommu_default_passthrough(void)
+{
+       return true;
+}
+
 static inline int iommu_attach_group(struct iommu_domain *domain,
                                     struct iommu_group *group)
 {
@@ -827,6 +885,16 @@ static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
        return NULL;
 }
 
+static inline void iommu_iotlb_gather_init(struct iommu_iotlb_gather *gather)
+{
+}
+
+static inline void iommu_iotlb_gather_add_page(struct iommu_domain *domain,
+                                              struct iommu_iotlb_gather *gather,
+                                              unsigned long iova, size_t size)
+{
+}
+
 static inline void iommu_device_unregister(struct iommu_device *iommu)
 {
 }
index b9b1bc5..f0b8092 100644 (file)
@@ -216,6 +216,29 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map,
                                       void **addr, unsigned long *sz);
 #endif /* CONFIG_KEXEC_FILE */
 
+#ifdef CONFIG_KEXEC_ELF
+struct kexec_elf_info {
+       /*
+        * Where the ELF binary contents are kept.
+        * Memory managed by the user of the struct.
+        */
+       const char *buffer;
+
+       const struct elfhdr *ehdr;
+       const struct elf_phdr *proghdrs;
+};
+
+int kexec_build_elf_info(const char *buf, size_t len, struct elfhdr *ehdr,
+                              struct kexec_elf_info *elf_info);
+
+int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
+                        struct kexec_elf_info *elf_info,
+                        struct kexec_buf *kbuf,
+                        unsigned long *lowest_load_addr);
+
+void kexec_free_elf_info(struct kexec_elf_info *elf_info);
+int kexec_elf_probe(const char *buf, unsigned long len);
+#endif
 struct kimage {
        kimage_entry_t head;
        kimage_entry_t *entry;
index 91f391c..5002833 100644 (file)
@@ -94,11 +94,11 @@ struct keyring_index_key {
        union {
                struct {
 #ifdef __LITTLE_ENDIAN /* Put desc_len at the LSB of x */
-                       u     desc_len;
-                       char    desc[sizeof(long) - 1]; /* First few chars of description */
+                       u16     desc_len;
+                       char    desc[sizeof(long) - 2]; /* First few chars of description */
 #else
-                       char    desc[sizeof(long) - 1]; /* First few chars of description */
-                       u     desc_len;
+                       char    desc[sizeof(long) - 2]; /* First few chars of description */
+                       u16     desc_len;
 #endif
                };
                unsigned long x;
index cbd9d84..88e1e63 100644 (file)
@@ -117,6 +117,7 @@ struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode);
 unsigned long logic_pio_trans_hwaddr(struct fwnode_handle *fwnode,
                        resource_size_t hw_addr, resource_size_t size);
 int logic_pio_register_range(struct logic_pio_hwaddr *newrange);
+void logic_pio_unregister_range(struct logic_pio_hwaddr *range);
 resource_size_t logic_pio_to_hwaddr(unsigned long pio);
 unsigned long logic_pio_trans_cpuaddr(resource_size_t hw_addr);
 
index 44c4146..2cd4359 100644 (file)
@@ -668,6 +668,7 @@ static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
 
 void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
                        int val);
+void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val);
 
 static inline void mod_lruvec_state(struct lruvec *lruvec,
                                    enum node_stat_item idx, int val)
@@ -1072,6 +1073,14 @@ static inline void mod_lruvec_page_state(struct page *page,
        mod_node_page_state(page_pgdat(page), idx, val);
 }
 
+static inline void __mod_lruvec_slab_state(void *p, enum node_stat_item idx,
+                                          int val)
+{
+       struct page *page = virt_to_head_page(p);
+
+       __mod_node_page_state(page_pgdat(page), idx, val);
+}
+
 static inline
 unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
@@ -1159,6 +1168,16 @@ static inline void __dec_lruvec_page_state(struct page *page,
        __mod_lruvec_page_state(page, idx, -1);
 }
 
+static inline void __inc_lruvec_slab_state(void *p, enum node_stat_item idx)
+{
+       __mod_lruvec_slab_state(p, idx, 1);
+}
+
+static inline void __dec_lruvec_slab_state(void *p, enum node_stat_item idx)
+{
+       __mod_lruvec_slab_state(p, idx, -1);
+}
+
 /* idx can be of type enum memcg_stat_item or node_stat_item */
 static inline void inc_memcg_state(struct mem_cgroup *memcg,
                                   int idx)
index 5228c62..bac395f 100644 (file)
@@ -139,6 +139,8 @@ struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
 struct mempolicy *get_task_policy(struct task_struct *p);
 struct mempolicy *__get_vma_policy(struct vm_area_struct *vma,
                unsigned long addr);
+struct mempolicy *get_vma_policy(struct vm_area_struct *vma,
+                                               unsigned long addr);
 bool vma_policy_mof(struct vm_area_struct *vma);
 
 extern void numa_default_policy(void);
index ce9839c..c2f056b 100644 (file)
@@ -446,11 +446,11 @@ enum {
 };
 
 enum {
-       MLX5_OPC_MOD_TLS_TIS_STATIC_PARAMS = 0x20,
+       MLX5_OPC_MOD_TLS_TIS_STATIC_PARAMS = 0x1,
 };
 
 enum {
-       MLX5_OPC_MOD_TLS_TIS_PROGRESS_PARAMS = 0x20,
+       MLX5_OPC_MOD_TLS_TIS_PROGRESS_PARAMS = 0x1,
 };
 
 enum {
index ec571fd..b8b570c 100644 (file)
@@ -10054,9 +10054,8 @@ struct mlx5_ifc_tls_static_params_bits {
 };
 
 struct mlx5_ifc_tls_progress_params_bits {
-       u8         valid[0x1];
-       u8         reserved_at_1[0x7];
-       u8         pd[0x18];
+       u8         reserved_at_0[0x8];
+       u8         tisn[0x18];
 
        u8         next_record_tcp_sn[0x20];
 
index 3a37a89..6a7a108 100644 (file)
@@ -159,7 +159,16 @@ struct page {
                        /** @pgmap: Points to the hosting device page map. */
                        struct dev_pagemap *pgmap;
                        void *zone_device_data;
-                       unsigned long _zd_pad_1;        /* uses mapping */
+                       /*
+                        * ZONE_DEVICE private pages are counted as being
+                        * mapped so the next 3 words hold the mapping, index,
+                        * and private fields from the source anonymous or
+                        * page cache page while the page is migrated to device
+                        * private memory.
+                        * ZONE_DEVICE MEMORY_DEVICE_FS_DAX pages also
+                        * use the mapping, index, and private fields when
+                        * pmem backed DAX files are mapped.
+                        */
                };
 
                /** @rcu_head: You can use this to free a page by RCU. */
index d77d717..3f38c30 100644 (file)
@@ -215,8 +215,9 @@ enum node_stat_item {
        NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
        NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
        NR_UNEVICTABLE,         /*  "     "     "   "       "         */
-       NR_SLAB_RECLAIMABLE,
-       NR_SLAB_UNRECLAIMABLE,
+       NR_SLAB_RECLAIMABLE,    /* Please do not reorder this item */
+       NR_SLAB_UNRECLAIMABLE,  /* and this one without looking at
+                                * memcg_flush_percpu_vmstats() first. */
        NR_ISOLATED_ANON,       /* Temporary isolated pages from anon lru */
        NR_ISOLATED_FILE,       /* Temporary isolated pages from file lru */
        WORKINGSET_NODES,
index 7a6871a..74c6f92 100644 (file)
@@ -4,6 +4,9 @@
  * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
  */
 
+#ifndef _NF_CONNTRACK_H323_TYPES_H
+#define _NF_CONNTRACK_H323_TYPES_H
+
 typedef struct TransportAddress_ipAddress {    /* SEQUENCE */
        int options;            /* No use */
        unsigned int ip;
@@ -931,3 +934,5 @@ typedef struct RasMessage { /* CHOICE */
                InfoRequestResponse infoRequestResponse;
        };
 } RasMessage;
+
+#endif /* _NF_CONNTRACK_H323_TYPES_H */
index f9737de..1696739 100644 (file)
@@ -61,10 +61,6 @@ static inline int of_mm_gpiochip_add(struct device_node *np,
 }
 extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 
-extern int of_gpio_simple_xlate(struct gpio_chip *gc,
-                               const struct of_phandle_args *gpiospec,
-                               u32 *flags);
-
 #else /* CONFIG_OF_GPIO */
 
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
@@ -77,13 +73,6 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
        return -ENOSYS;
 }
 
-static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
-                                      const struct of_phandle_args *gpiospec,
-                                      u32 *flags)
-{
-       return -ENOSYS;
-}
-
 #endif /* CONFIG_OF_GPIO */
 
 /**
index 153bf25..2c32ca0 100644 (file)
 #ifndef _OMAP_IOMMU_H_
 #define _OMAP_IOMMU_H_
 
+struct iommu_domain;
+
 #ifdef CONFIG_OMAP_IOMMU
 extern void omap_iommu_save_ctx(struct device *dev);
 extern void omap_iommu_restore_ctx(struct device *dev);
+
+int omap_iommu_domain_deactivate(struct iommu_domain *domain);
+int omap_iommu_domain_activate(struct iommu_domain *domain);
 #else
 static inline void omap_iommu_save_ctx(struct device *dev) {}
 static inline void omap_iommu_restore_ctx(struct device *dev) {}
+
+static inline int omap_iommu_domain_deactivate(struct iommu_domain *domain)
+{
+       return -ENODEV;
+}
+
+static inline int omap_iommu_domain_activate(struct iommu_domain *domain)
+{
+       return -ENODEV;
+}
 #endif
 
 #endif
index 9e700d9..82e4cd1 100644 (file)
@@ -1567,8 +1567,10 @@ extern bool pcie_ports_native;
 
 #ifdef CONFIG_PCIEASPM
 bool pcie_aspm_support_enabled(void);
+bool pcie_aspm_enabled(struct pci_dev *pdev);
 #else
 static inline bool pcie_aspm_support_enabled(void) { return false; }
+static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; }
 #endif
 
 #ifdef CONFIG_PCIEAER
index c842735..24486f4 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_DF_F3    0x1463
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493
+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
 #define PCI_DEVICE_ID_AMD_CNB17H_F3    0x1703
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
 #define PCI_VENDOR_ID_SGI              0x10a9
 #define PCI_DEVICE_ID_SGI_IOC3         0x0003
 #define PCI_DEVICE_ID_SGI_LITHIUM      0x1002
-#define PCI_DEVICE_ID_SGI_IOC4         0x100a
 
 #define PCI_VENDOR_ID_WINBOND          0x10ad
 #define PCI_DEVICE_ID_WINBOND_82C105   0x0105
index 462b90b..2fb9c8f 100644 (file)
@@ -1107,6 +1107,7 @@ int genphy_c45_an_disable_aneg(struct phy_device *phydev);
 int genphy_c45_read_mdix(struct phy_device *phydev);
 int genphy_c45_pma_read_abilities(struct phy_device *phydev);
 int genphy_c45_read_status(struct phy_device *phydev);
+int genphy_c45_config_aneg(struct phy_device *phydev);
 
 /* The gen10g_* functions are the old Clause 45 stub */
 int gen10g_config_aneg(struct phy_device *phydev);
index 1e5d86e..52bc8e4 100644 (file)
@@ -11,6 +11,7 @@ struct fixed_phy_status {
 };
 
 struct device_node;
+struct gpio_desc;
 
 #if IS_ENABLED(CONFIG_FIXED_PHY)
 extern int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier);
index 2a83e43..9645b11 100644 (file)
@@ -72,6 +72,10 @@ extern struct pid init_struct_pid;
 
 extern const struct file_operations pidfd_fops;
 
+struct file;
+
+extern struct pid *pidfd_pid(const struct file *file);
+
 static inline struct pid *get_pid(struct pid *pid)
 {
        if (pid)
index 9a3e780..eaefba0 100644 (file)
@@ -50,7 +50,4 @@ struct htc_egpio_platform_data {
        int                   num_chips;
 };
 
-/* Determine the wakeup irq, to be called during early resume */
-extern int htc_egpio_get_wakeup_irq(struct device *dev);
-
 #endif
index 44d913a..8474a02 100644 (file)
@@ -13,4 +13,8 @@ struct iommu_platform_data {
        const char *reset_name;
        int (*assert_reset)(struct platform_device *pdev, const char *name);
        int (*deassert_reset)(struct platform_device *pdev, const char *name);
+       int (*device_enable)(struct platform_device *pdev);
+       int (*device_idle)(struct platform_device *pdev);
+       int (*set_pwrdm_constraint)(struct platform_device *pdev, bool request,
+                                   u8 *pwrst);
 };
index a8a1561..e2bacc6 100644 (file)
@@ -15,8 +15,8 @@
 
 bool psci_tos_resident_on(int cpu);
 
-int psci_cpu_init_idle(unsigned int cpu);
-int psci_cpu_suspend_enter(unsigned long index);
+int psci_cpu_suspend_enter(u32 state);
+bool psci_power_state_is_valid(u32 state);
 
 enum psci_conduit {
        PSCI_CONDUIT_NONE,
index 1f7dced..f189c92 100644 (file)
@@ -19,6 +19,7 @@ struct random_ready_callback {
 };
 
 extern void add_device_randomness(const void *, unsigned int);
+extern void add_bootloader_randomness(const void *, unsigned int);
 
 #if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
 static inline void add_latent_entropy(void)
index 8159834..337a463 100644 (file)
@@ -281,6 +281,12 @@ void devm_regulator_unregister_notifier(struct regulator *regulator,
 void *regulator_get_drvdata(struct regulator *regulator);
 void regulator_set_drvdata(struct regulator *regulator, void *data);
 
+/* misc helpers */
+
+void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                                    const char *const *supply_names,
+                                    unsigned int num_supplies);
+
 #else
 
 /*
@@ -580,6 +586,13 @@ static inline int regulator_list_voltage(struct regulator *regulator, unsigned s
        return -EINVAL;
 }
 
+static inline void
+regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers,
+                               const char *const *supply_names,
+                               unsigned int num_supplies)
+{
+}
+
 #endif
 
 static inline int regulator_set_voltage_triplet(struct regulator *regulator,
diff --git a/include/linux/regulator/mt6358-regulator.h b/include/linux/regulator/mt6358-regulator.h
new file mode 100644 (file)
index 0000000..1cc3049
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6358_H
+#define __LINUX_REGULATOR_MT6358_H
+
+enum {
+       MT6358_ID_VDRAM1 = 0,
+       MT6358_ID_VCORE,
+       MT6358_ID_VPA,
+       MT6358_ID_VPROC11,
+       MT6358_ID_VPROC12,
+       MT6358_ID_VGPU,
+       MT6358_ID_VS2,
+       MT6358_ID_VMODEM,
+       MT6358_ID_VS1,
+       MT6358_ID_VDRAM2 = 9,
+       MT6358_ID_VSIM1,
+       MT6358_ID_VIBR,
+       MT6358_ID_VRF12,
+       MT6358_ID_VIO18,
+       MT6358_ID_VUSB,
+       MT6358_ID_VCAMIO,
+       MT6358_ID_VCAMD,
+       MT6358_ID_VCN18,
+       MT6358_ID_VFE28,
+       MT6358_ID_VSRAM_PROC11,
+       MT6358_ID_VCN28,
+       MT6358_ID_VSRAM_OTHERS,
+       MT6358_ID_VSRAM_GPU,
+       MT6358_ID_VXO22,
+       MT6358_ID_VEFUSE,
+       MT6358_ID_VAUX18,
+       MT6358_ID_VMCH,
+       MT6358_ID_VBIF28,
+       MT6358_ID_VSRAM_PROC12,
+       MT6358_ID_VCAMA1,
+       MT6358_ID_VEMC,
+       MT6358_ID_VIO28,
+       MT6358_ID_VA12,
+       MT6358_ID_VRF18,
+       MT6358_ID_VCN33_BT,
+       MT6358_ID_VCN33_WIFI,
+       MT6358_ID_VCAMA2,
+       MT6358_ID_VMC,
+       MT6358_ID_VLDO28,
+       MT6358_ID_VAUD28,
+       MT6358_ID_VSIM2,
+       MT6358_ID_RG_MAX,
+};
+
+#define MT6358_MAX_REGULATOR   MT6358_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6358_H */
index b5d9948..1a5f883 100644 (file)
@@ -282,6 +282,9 @@ extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping);
 extern void exit_signals(struct task_struct *tsk);
 extern void kernel_sigaction(int, __sighandler_t);
 
+#define SIG_KTHREAD ((__force __sighandler_t)2)
+#define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3)
+
 static inline void allow_signal(int sig)
 {
        /*
@@ -289,7 +292,17 @@ static inline void allow_signal(int sig)
         * know it'll be handled, so that they don't get converted to
         * SIGKILL or just silently dropped.
         */
-       kernel_sigaction(sig, (__force __sighandler_t)2);
+       kernel_sigaction(sig, SIG_KTHREAD);
+}
+
+static inline void allow_kernel_signal(int sig)
+{
+       /*
+        * Kernel threads handle their own signals. Let the signal code
+        * know signals sent by the kernel will be handled, so that they
+        * don't get silently dropped.
+        */
+       kernel_sigaction(sig, SIG_KTHREAD_KERNEL);
 }
 
 static inline void disallow_signal(int sig)
index d8af86d..ba55835 100644 (file)
@@ -1374,6 +1374,14 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
+static inline void skb_copy_decrypted(struct sk_buff *to,
+                                     const struct sk_buff *from)
+{
+#ifdef CONFIG_TLS_DEVICE
+       to->decrypted = from->decrypted;
+#endif
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
index 9752381..fc0bed5 100644 (file)
@@ -292,6 +292,9 @@ struct ucred {
 #define MSG_BATCH      0x40000 /* sendmmsg(): more messages coming */
 #define MSG_EOF         MSG_FIN
 #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */
+#define MSG_SENDPAGE_DECRYPTED 0x100000 /* sendpage() internal : page may carry
+                                         * plain text and require encryption
+                                         */
 
 #define MSG_ZEROCOPY   0x4000000       /* Use user data in kernel path */
 #define MSG_FASTOPEN   0x20000000      /* Send data in TCP SYN */
index baa3ecd..27536b9 100644 (file)
@@ -98,7 +98,6 @@ typedef void                  (*rpc_action)(struct rpc_task *);
 
 struct rpc_call_ops {
        void (*rpc_call_prepare)(struct rpc_task *, void *);
-       void (*rpc_call_prepare_transmit)(struct rpc_task *, void *);
        void (*rpc_call_done)(struct rpc_task *, void *);
        void (*rpc_count_stats)(struct rpc_task *, void *);
        void (*rpc_release)(void *);
index 361f62b..cde3dc1 100644 (file)
@@ -46,13 +46,17 @@ enum dma_sync_target {
 
 extern phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
                                          dma_addr_t tbl_dma_addr,
-                                         phys_addr_t phys, size_t size,
+                                         phys_addr_t phys,
+                                         size_t mapping_size,
+                                         size_t alloc_size,
                                          enum dma_data_direction dir,
                                          unsigned long attrs);
 
 extern void swiotlb_tbl_unmap_single(struct device *hwdev,
                                     phys_addr_t tlb_addr,
-                                    size_t size, enum dma_data_direction dir,
+                                    size_t mapping_size,
+                                    size_t alloc_size,
+                                    enum dma_data_direction dir,
                                     unsigned long attrs);
 
 extern void swiotlb_tbl_sync_single(struct device *hwdev,
index 88145da..f7c561c 100644 (file)
@@ -1402,4 +1402,23 @@ static inline unsigned int ksys_personality(unsigned int personality)
        return old;
 }
 
+/* for __ARCH_WANT_SYS_IPC */
+long ksys_semtimedop(int semid, struct sembuf __user *tsops,
+                    unsigned int nsops,
+                    const struct __kernel_timespec __user *timeout);
+long ksys_semget(key_t key, int nsems, int semflg);
+long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
+long ksys_msgget(key_t key, int msgflg);
+long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
+long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
+                long msgtyp, int msgflg);
+long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
+                int msgflg);
+long ksys_shmget(key_t key, size_t size, int shmflg);
+long ksys_shmdt(char __user *shmaddr);
+long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
+long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
+                           unsigned int nsops,
+                           const struct old_timespec32 __user *timeout);
+
 #endif
index 7acb953..84ff284 100644 (file)
@@ -57,6 +57,7 @@ struct tk_read_base {
  * @cs_was_changed_seq:        The sequence number of clocksource change events
  * @next_leap_ktime:   CLOCK_MONOTONIC time value of a pending leap-second
  * @raw_sec:           CLOCK_MONOTONIC_RAW  time in seconds
+ * @monotonic_to_boot: CLOCK_MONOTONIC to CLOCK_BOOTTIME offset
  * @cycle_interval:    Number of clock cycles in one NTP interval
  * @xtime_interval:    Number of clock shifted nano seconds in one NTP
  *                     interval.
@@ -84,6 +85,9 @@ struct tk_read_base {
  *
  * wall_to_monotonic is no longer the boot time, getboottime must be
  * used instead.
+ *
+ * @monotonic_to_boottime is a timespec64 representation of @offs_boot to
+ * accelerate the VDSO update for CLOCK_BOOTTIME.
  */
 struct timekeeper {
        struct tk_read_base     tkr_mono;
@@ -99,6 +103,7 @@ struct timekeeper {
        u8                      cs_was_changed_seq;
        ktime_t                 next_leap_ktime;
        u64                     raw_sec;
+       struct timespec64       monotonic_to_boot;
 
        /* The following members are for timekeeping internal use */
        u64                     cycle_interval;
index 47a3e3c..2a19d19 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef _LINUX_TOPOLOGY_H
 #define _LINUX_TOPOLOGY_H
 
+#include <linux/arch_topology.h>
 #include <linux/cpumask.h>
 #include <linux/bitops.h>
 #include <linux/mmzone.h>
index 5150436..30a8cdc 100644 (file)
@@ -548,6 +548,7 @@ extern int trace_event_get_offsets(struct trace_event_call *call);
 
 #define is_signed_type(type)   (((type)(-1)) < (type)1)
 
+int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set);
 int trace_set_clr_event(const char *system, const char *event, int set);
 
 /*
index 83d35d9..e87826e 100644 (file)
@@ -1457,7 +1457,7 @@ typedef void (*usb_complete_t)(struct urb *);
  * field rather than determining a dma address themselves.
  *
  * Note that transfer_buffer must still be set if the controller
- * does not support DMA (as indicated by bus.uses_dma) and when talking
+ * does not support DMA (as indicated by hcd_uses_dma()) and when talking
  * to root hub. If you have to trasfer between highmem zone and the device
  * on such controller, create a bounce buffer or bail out with an error.
  * If transfer_buffer cannot be set (is in highmem) and the controller is DMA
index bab27cc..a20e781 100644 (file)
@@ -422,6 +422,9 @@ static inline bool hcd_periodic_completion_in_progress(struct usb_hcd *hcd,
        return hcd->high_prio_bh.completing_ep == ep;
 }
 
+#define hcd_uses_dma(hcd) \
+       (IS_ENABLED(CONFIG_HAS_DMA) && (hcd)->self.uses_dma)
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);
index f37d128..adcc6a9 100644 (file)
@@ -308,6 +308,7 @@ do {                                                                             \
                                                                             \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                          \
     R##_e = X##_e;                                                          \
+         /* Fall through */                                                 \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                           \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                              \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                                     \
@@ -318,6 +319,7 @@ do {                                                                             \
                                                                             \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                          \
     R##_e = Y##_e;                                                          \
+         /* Fall through */                                                 \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                           \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                              \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                                     \
@@ -415,6 +417,7 @@ do {                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):         \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                \
     R##_s = X##_s;                                     \
+       /* Fall through */                              \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
@@ -428,6 +431,7 @@ do {                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):         \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                \
     R##_s = Y##_s;                                     \
+       /* Fall through */                              \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):      \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
@@ -493,6 +497,7 @@ do {                                                        \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
     FP_SET_EXCEPTION(FP_EX_DIVZERO);                   \
+         /* Fall through */                            \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
     R##_c = FP_CLS_INF;                                        \
diff --git a/include/misc/charlcd.h b/include/misc/charlcd.h
deleted file mode 100644 (file)
index 8cf6c18..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Character LCD driver for Linux
- *
- * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
- * Copyright (C) 2016-2017 Glider bvba
- */
-
-struct charlcd {
-       const struct charlcd_ops *ops;
-       const unsigned char *char_conv; /* Optional */
-
-       int ifwidth;                    /* 4-bit or 8-bit (default) */
-       int height;
-       int width;
-       int bwidth;                     /* Default set by charlcd_alloc() */
-       int hwidth;                     /* Default set by charlcd_alloc() */
-
-       void *drvdata;                  /* Set by charlcd_alloc() */
-};
-
-struct charlcd_ops {
-       /* Required */
-       void (*write_cmd)(struct charlcd *lcd, int cmd);
-       void (*write_data)(struct charlcd *lcd, int data);
-
-       /* Optional */
-       void (*write_cmd_raw4)(struct charlcd *lcd, int cmd);   /* 4-bit only */
-       void (*clear_fast)(struct charlcd *lcd);
-       void (*backlight)(struct charlcd *lcd, int on);
-};
-
-struct charlcd *charlcd_alloc(unsigned int drvdata_size);
-void charlcd_free(struct charlcd *lcd);
-
-int charlcd_register(struct charlcd *lcd);
-int charlcd_unregister(struct charlcd *lcd);
-
-void charlcd_poke(struct charlcd *lcd);
index c61a1bf..3a1a729 100644 (file)
@@ -15,6 +15,7 @@
 struct tcf_idrinfo {
        struct mutex    lock;
        struct idr      action_idr;
+       struct net      *net;
 };
 
 struct tc_action_ops;
@@ -108,7 +109,7 @@ struct tc_action_net {
 };
 
 static inline
-int tc_action_net_init(struct tc_action_net *tn,
+int tc_action_net_init(struct net *net, struct tc_action_net *tn,
                       const struct tc_action_ops *ops)
 {
        int err = 0;
@@ -117,6 +118,7 @@ int tc_action_net_init(struct tc_action_net *tn,
        if (!tn->idrinfo)
                return -ENOMEM;
        tn->ops = ops;
+       tn->idrinfo->net = net;
        mutex_init(&tn->idrinfo->lock);
        idr_init(&tn->idrinfo->action_idr);
        return err;
index becdad5..3f62b34 100644 (file)
@@ -206,7 +206,7 @@ static inline int ipv6_mc_may_pull(struct sk_buff *skb,
                                   unsigned int len)
 {
        if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
-               return -EINVAL;
+               return 0;
 
        return pskb_may_pull(skb, len);
 }
index ded574b..ffc95b3 100644 (file)
@@ -278,6 +278,7 @@ struct hci_dev {
        __u16           conn_info_min_age;
        __u16           conn_info_max_age;
        __u16           auth_payload_timeout;
+       __u8            min_enc_key_size;
        __u8            ssp_debug_mode;
        __u8            hw_error_code;
        __u32           clock;
index 010f26b..bac79e8 100644 (file)
@@ -171,7 +171,7 @@ int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
 void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
                              struct sk_buff *parent);
 void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
-                           void *reasm_data);
+                           void *reasm_data, bool try_coalesce);
 struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q);
 
 #endif
index 4c81846..ab1ca9e 100644 (file)
@@ -513,7 +513,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
                          struct netlink_callback *cb);
 
 int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh,
-                    unsigned char *flags, bool skip_oif);
+                    u8 rt_family, unsigned char *flags, bool skip_oif);
 int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh,
-                   int nh_weight);
+                   int nh_weight, u8 rt_family);
 #endif  /* _NET_FIB_H */
index 4a9da95..ab40d7a 100644 (file)
@@ -52,7 +52,7 @@ struct bpf_prog;
 #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
 
 struct net {
-       refcount_t              passive;        /* To decided when the network
+       refcount_t              passive;        /* To decide when the network
                                                 * namespace should be freed.
                                                 */
        refcount_t              count;          /* To decided when the network
@@ -61,7 +61,6 @@ struct net {
        spinlock_t              rules_mod_lock;
 
        u32                     hash_mix;
-       atomic64_t              cookie_gen;
 
        struct list_head        list;           /* list of network namespaces */
        struct list_head        exit_list;      /* To linked to call pernet exit
index 9b62456..475d6f2 100644 (file)
@@ -421,8 +421,7 @@ struct nft_set {
        unsigned char                   *udata;
        /* runtime data below here */
        const struct nft_set_ops        *ops ____cacheline_aligned;
-       u16                             flags:13,
-                                       bound:1,
+       u16                             flags:14,
                                        genmask:2;
        u8                              klen;
        u8                              dlen;
@@ -1348,12 +1347,15 @@ struct nft_trans_rule {
 struct nft_trans_set {
        struct nft_set                  *set;
        u32                             set_id;
+       bool                            bound;
 };
 
 #define nft_trans_set(trans)   \
        (((struct nft_trans_set *)trans->data)->set)
 #define nft_trans_set_id(trans)        \
        (((struct nft_trans_set *)trans->data)->set_id)
+#define nft_trans_set_bound(trans)     \
+       (((struct nft_trans_set *)trans->data)->bound)
 
 struct nft_trans_chain {
        bool                            update;
@@ -1384,12 +1386,15 @@ struct nft_trans_table {
 struct nft_trans_elem {
        struct nft_set                  *set;
        struct nft_set_elem             elem;
+       bool                            bound;
 };
 
 #define nft_trans_elem_set(trans)      \
        (((struct nft_trans_elem *)trans->data)->set)
 #define nft_trans_elem(trans)  \
        (((struct nft_trans_elem *)trans->data)->elem)
+#define nft_trans_elem_set_bound(trans)        \
+       (((struct nft_trans_elem *)trans->data)->bound)
 
 struct nft_trans_obj {
        struct nft_object               *obj;
index 3196663..c8b9dec 100644 (file)
@@ -73,4 +73,6 @@ int nft_flow_rule_offload_commit(struct net *net);
        (__reg)->key            = __key;                                \
        memset(&(__reg)->mask, 0xff, (__reg)->len);
 
+int nft_chain_offload_priority(struct nft_base_chain *basechain);
+
 #endif
index e4650e5..b140c8f 100644 (file)
@@ -684,9 +684,8 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
                              const struct nla_policy *policy,
                              struct netlink_ext_ack *extack)
 {
-       return __nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
-                          nlmsg_attrlen(nlh, hdrlen), policy,
-                          NL_VALIDATE_STRICT, extack);
+       return __nlmsg_parse(nlh, hdrlen, tb, maxtype, policy,
+                            NL_VALIDATE_STRICT, extack);
 }
 
 /**
index 25f1f9a..331ebbc 100644 (file)
@@ -141,12 +141,6 @@ static inline unsigned int nexthop_num_path(const struct nexthop *nh)
 
                nh_grp = rcu_dereference_rtnl(nh->nh_grp);
                rc = nh_grp->num_nh;
-       } else {
-               const struct nh_info *nhi;
-
-               nhi = rcu_dereference_rtnl(nh->nh_info);
-               if (nhi->reject_nh)
-                       rc = 0;
        }
 
        return rc;
@@ -167,7 +161,8 @@ struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
 }
 
 static inline
-int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
+int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
+                           u8 rt_family)
 {
        struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
        int i;
@@ -178,7 +173,7 @@ int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
                struct fib_nh_common *nhc = &nhi->fib_nhc;
                int weight = nhg->nh_entries[i].weight;
 
-               if (fib_add_nexthop(skb, nhc, weight) < 0)
+               if (fib_add_nexthop(skb, nhc, weight, rt_family) < 0)
                        return -EMSGSIZE;
        }
 
index e429809..98be18e 100644 (file)
@@ -646,7 +646,7 @@ tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
 {
        cls_common->chain_index = tp->chain->index;
        cls_common->protocol = tp->protocol;
-       cls_common->prio = tp->prio;
+       cls_common->prio = tp->prio >> 16;
        if (tc_skip_sw(flags) || flags & TCA_CLS_FLAGS_VERBOSE)
                cls_common->extack = extack;
 }
index 37a4df2..6b578ce 100644 (file)
@@ -11,6 +11,7 @@ struct psample_group {
        u32 group_num;
        u32 refcount;
        u32 seq;
+       struct rcu_head rcu;
 };
 
 struct psample_group *psample_group_get(struct net *net, u32 group_num);
index 630a049..dfce19c 100644 (file)
@@ -233,7 +233,7 @@ void rt_del_uncached_list(struct rtable *rt);
 
 int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
                       u32 table_id, struct fib_info *fi,
-                      int *fa_index, int fa_start);
+                      int *fa_index, int fa_start, unsigned int flags);
 
 static inline void ip_rt_put(struct rtable *rt)
 {
index 228db39..2c53f1a 100644 (file)
@@ -2482,6 +2482,7 @@ static inline bool sk_fullsock(const struct sock *sk)
 
 /* Checks if this SKB belongs to an HW offloaded socket
  * and whether any SW fallbacks are required based on dev.
+ * Check decrypted mark in case skb_orphan() cleared socket.
  */
 static inline struct sk_buff *sk_validate_xmit_skb(struct sk_buff *skb,
                                                   struct net_device *dev)
@@ -2489,8 +2490,15 @@ static inline struct sk_buff *sk_validate_xmit_skb(struct sk_buff *skb,
 #ifdef CONFIG_SOCK_VALIDATE_XMIT
        struct sock *sk = skb->sk;
 
-       if (sk && sk_fullsock(sk) && sk->sk_validate_xmit_skb)
+       if (sk && sk_fullsock(sk) && sk->sk_validate_xmit_skb) {
                skb = sk->sk_validate_xmit_skb(sk, dev, skb);
+#ifdef CONFIG_TLS_DEVICE
+       } else if (unlikely(skb->decrypted)) {
+               pr_warn_ratelimited("unencrypted skb with no associated socket - dropping\n");
+               kfree_skb(skb);
+               skb = NULL;
+#endif
+       }
 #endif
 
        return skb;
index b22db30..aa08a7a 100644 (file)
@@ -983,7 +983,6 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
 void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
 
 struct xfrm_if_parms {
-       char name[IFNAMSIZ];    /* name of XFRM device */
        int link;               /* ifindex of underlying L2 interface */
        u32 if_id;              /* interface identifyer */
 };
@@ -991,7 +990,6 @@ struct xfrm_if_parms {
 struct xfrm_if {
        struct xfrm_if __rcu *next;     /* next interface in list */
        struct net_device *dev;         /* virtual device associated with interface */
-       struct net_device *phydev;      /* physical device */
        struct net *net;                /* netns for packet i/o */
        struct xfrm_if_parms p;         /* interface parms */
 
index b0fc6b2..83df1ec 100644 (file)
@@ -105,8 +105,7 @@ struct rdma_restrack_entry {
 };
 
 int rdma_restrack_count(struct ib_device *dev,
-                       enum rdma_restrack_type type,
-                       struct pid_namespace *ns);
+                       enum rdma_restrack_type type);
 
 void rdma_restrack_kadd(struct rdma_restrack_entry *res);
 void rdma_restrack_uadd(struct rdma_restrack_entry *res);
index 50f49e0..d1a93c7 100644 (file)
@@ -46,7 +46,9 @@ struct mcip_cmd {
 #define CMD_IDU_ENABLE                 0x71
 #define CMD_IDU_DISABLE                        0x72
 #define CMD_IDU_SET_MODE               0x74
+#define CMD_IDU_READ_MODE              0x75
 #define CMD_IDU_SET_DEST               0x76
+#define CMD_IDU_ACK_CIRQ               0x79
 #define CMD_IDU_SET_MASK               0x7C
 
 #define IDU_M_TRIG_LEVEL               0x0
@@ -119,4 +121,13 @@ static inline void __mcip_cmd_data(unsigned int cmd, unsigned int param,
        __mcip_cmd(cmd, param);
 }
 
+/*
+ * Read MCIP register
+ */
+static inline unsigned int __mcip_cmd_read(unsigned int cmd, unsigned int param)
+{
+       __mcip_cmd(cmd, param);
+       return read_aux_reg(ARC_REG_MCIP_READBACK);
+}
+
 #endif
index 79b74ce..5a34b87 100644 (file)
@@ -20,11 +20,6 @@ struct mtk_smi_larb_iommu {
        unsigned int   mmu;
 };
 
-struct mtk_smi_iommu {
-       unsigned int larb_nr;
-       struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
-};
-
 /*
  * mtk_smi_larb_get: Enable the power domain and clocks for this local arbiter.
  *                   It also initialize some basic setting(like iommu).
diff --git a/include/trace/events/intel_iommu.h b/include/trace/events/intel_iommu.h
new file mode 100644 (file)
index 0000000..54e61d4
--- /dev/null
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Intel IOMMU trace support
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ */
+#ifdef CONFIG_INTEL_IOMMU
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel_iommu
+
+#if !defined(_TRACE_INTEL_IOMMU_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTEL_IOMMU_H
+
+#include <linux/tracepoint.h>
+#include <linux/intel-iommu.h>
+
+DECLARE_EVENT_CLASS(dma_map,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, phys_addr_t phys_addr,
+                size_t size),
+
+       TP_ARGS(dev, dev_addr, phys_addr, size),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name(dev))
+               __field(dma_addr_t, dev_addr)
+               __field(phys_addr_t, phys_addr)
+               __field(size_t, size)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name(dev));
+               __entry->dev_addr = dev_addr;
+               __entry->phys_addr = phys_addr;
+               __entry->size = size;
+       ),
+
+       TP_printk("dev=%s dev_addr=0x%llx phys_addr=0x%llx size=%zu",
+                 __get_str(dev_name),
+                 (unsigned long long)__entry->dev_addr,
+                 (unsigned long long)__entry->phys_addr,
+                 __entry->size)
+);
+
+DEFINE_EVENT(dma_map, map_single,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, phys_addr_t phys_addr,
+                size_t size),
+       TP_ARGS(dev, dev_addr, phys_addr, size)
+);
+
+DEFINE_EVENT(dma_map, map_sg,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, phys_addr_t phys_addr,
+                size_t size),
+       TP_ARGS(dev, dev_addr, phys_addr, size)
+);
+
+DEFINE_EVENT(dma_map, bounce_map_single,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, phys_addr_t phys_addr,
+                size_t size),
+       TP_ARGS(dev, dev_addr, phys_addr, size)
+);
+
+DECLARE_EVENT_CLASS(dma_unmap,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, size_t size),
+
+       TP_ARGS(dev, dev_addr, size),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name(dev))
+               __field(dma_addr_t, dev_addr)
+               __field(size_t, size)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name(dev));
+               __entry->dev_addr = dev_addr;
+               __entry->size = size;
+       ),
+
+       TP_printk("dev=%s dev_addr=0x%llx size=%zu",
+                 __get_str(dev_name),
+                 (unsigned long long)__entry->dev_addr,
+                 __entry->size)
+);
+
+DEFINE_EVENT(dma_unmap, unmap_single,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, size_t size),
+       TP_ARGS(dev, dev_addr, size)
+);
+
+DEFINE_EVENT(dma_unmap, unmap_sg,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, size_t size),
+       TP_ARGS(dev, dev_addr, size)
+);
+
+DEFINE_EVENT(dma_unmap, bounce_unmap_single,
+       TP_PROTO(struct device *dev, dma_addr_t dev_addr, size_t size),
+       TP_ARGS(dev, dev_addr, size)
+);
+
+#endif /* _TRACE_INTEL_IOMMU_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+#endif /* CONFIG_INTEL_IOMMU */
index cc1d060..a13a62d 100644 (file)
 #define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY
 
 enum rxrpc_skb_trace {
-       rxrpc_skb_rx_cleaned,
-       rxrpc_skb_rx_freed,
-       rxrpc_skb_rx_got,
-       rxrpc_skb_rx_lost,
-       rxrpc_skb_rx_purged,
-       rxrpc_skb_rx_received,
-       rxrpc_skb_rx_rotated,
-       rxrpc_skb_rx_seen,
-       rxrpc_skb_tx_cleaned,
-       rxrpc_skb_tx_freed,
-       rxrpc_skb_tx_got,
-       rxrpc_skb_tx_new,
-       rxrpc_skb_tx_rotated,
-       rxrpc_skb_tx_seen,
+       rxrpc_skb_cleaned,
+       rxrpc_skb_freed,
+       rxrpc_skb_got,
+       rxrpc_skb_lost,
+       rxrpc_skb_new,
+       rxrpc_skb_purged,
+       rxrpc_skb_received,
+       rxrpc_skb_rotated,
+       rxrpc_skb_seen,
+       rxrpc_skb_unshared,
+       rxrpc_skb_unshared_nomem,
 };
 
 enum rxrpc_local_trace {
@@ -228,20 +225,17 @@ enum rxrpc_tx_point {
  * Declare tracing information enums and their string mappings for display.
  */
 #define rxrpc_skb_traces \
-       EM(rxrpc_skb_rx_cleaned,                "Rx CLN") \
-       EM(rxrpc_skb_rx_freed,                  "Rx FRE") \
-       EM(rxrpc_skb_rx_got,                    "Rx GOT") \
-       EM(rxrpc_skb_rx_lost,                   "Rx *L*") \
-       EM(rxrpc_skb_rx_purged,                 "Rx PUR") \
-       EM(rxrpc_skb_rx_received,               "Rx RCV") \
-       EM(rxrpc_skb_rx_rotated,                "Rx ROT") \
-       EM(rxrpc_skb_rx_seen,                   "Rx SEE") \
-       EM(rxrpc_skb_tx_cleaned,                "Tx CLN") \
-       EM(rxrpc_skb_tx_freed,                  "Tx FRE") \
-       EM(rxrpc_skb_tx_got,                    "Tx GOT") \
-       EM(rxrpc_skb_tx_new,                    "Tx NEW") \
-       EM(rxrpc_skb_tx_rotated,                "Tx ROT") \
-       E_(rxrpc_skb_tx_seen,                   "Tx SEE")
+       EM(rxrpc_skb_cleaned,                   "CLN") \
+       EM(rxrpc_skb_freed,                     "FRE") \
+       EM(rxrpc_skb_got,                       "GOT") \
+       EM(rxrpc_skb_lost,                      "*L*") \
+       EM(rxrpc_skb_new,                       "NEW") \
+       EM(rxrpc_skb_purged,                    "PUR") \
+       EM(rxrpc_skb_received,                  "RCV") \
+       EM(rxrpc_skb_rotated,                   "ROT") \
+       EM(rxrpc_skb_seen,                      "SEE") \
+       EM(rxrpc_skb_unshared,                  "UNS") \
+       E_(rxrpc_skb_unshared_nomem,            "US0")
 
 #define rxrpc_local_traces \
        EM(rxrpc_local_got,                     "GOT") \
@@ -498,10 +492,10 @@ rxrpc_tx_points;
 #define E_(a, b)       { a, b }
 
 TRACE_EVENT(rxrpc_local,
-           TP_PROTO(struct rxrpc_local *local, enum rxrpc_local_trace op,
+           TP_PROTO(unsigned int local_debug_id, enum rxrpc_local_trace op,
                     int usage, const void *where),
 
-           TP_ARGS(local, op, usage, where),
+           TP_ARGS(local_debug_id, op, usage, where),
 
            TP_STRUCT__entry(
                    __field(unsigned int,       local           )
@@ -511,7 +505,7 @@ TRACE_EVENT(rxrpc_local,
                             ),
 
            TP_fast_assign(
-                   __entry->local = local->debug_id;
+                   __entry->local = local_debug_id;
                    __entry->op = op;
                    __entry->usage = usage;
                    __entry->where = where;
@@ -643,13 +637,14 @@ TRACE_EVENT(rxrpc_call,
 
 TRACE_EVENT(rxrpc_skb,
            TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op,
-                    int usage, int mod_count, const void *where),
+                    int usage, int mod_count, u8 flags,    const void *where),
 
-           TP_ARGS(skb, op, usage, mod_count, where),
+           TP_ARGS(skb, op, usage, mod_count, flags, where),
 
            TP_STRUCT__entry(
                    __field(struct sk_buff *,           skb             )
                    __field(enum rxrpc_skb_trace,       op              )
+                   __field(u8,                         flags           )
                    __field(int,                        usage           )
                    __field(int,                        mod_count       )
                    __field(const void *,               where           )
@@ -657,14 +652,16 @@ TRACE_EVENT(rxrpc_skb,
 
            TP_fast_assign(
                    __entry->skb = skb;
+                   __entry->flags = flags;
                    __entry->op = op;
                    __entry->usage = usage;
                    __entry->mod_count = mod_count;
                    __entry->where = where;
                           ),
 
-           TP_printk("s=%p %s u=%d m=%d p=%pSR",
+           TP_printk("s=%p %cx %s u=%d m=%d p=%pSR",
                      __entry->skb,
+                     __entry->flags & RXRPC_SKB_TX_BUFFER ? 'T' : 'R',
                      __print_symbolic(__entry->op, rxrpc_skb_traces),
                      __entry->usage,
                      __entry->mod_count,
index 1be0e79..1fc8faa 100644 (file)
@@ -569,7 +569,7 @@ __SYSCALL(__NR_semget, sys_semget)
 __SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl)
 #if defined(__ARCH_WANT_TIME32_SYSCALLS) || __BITS_PER_LONG != 32
 #define __NR_semtimedop 192
-__SC_COMP(__NR_semtimedop, sys_semtimedop, sys_semtimedop_time32)
+__SC_3264(__NR_semtimedop, sys_semtimedop_time32, sys_semtimedop)
 #endif
 #define __NR_semop 193
 __SYSCALL(__NR_semop, sys_semop)
index fa1c753..a5aa7d3 100644 (file)
@@ -1466,8 +1466,8 @@ union bpf_attr {
  *             If no cookie has been set yet, generate a new cookie. Once
  *             generated, the socket cookie remains stable for the life of the
  *             socket. This helper can be useful for monitoring per socket
- *             networking traffic statistics as it provides a unique socket
- *             identifier per namespace.
+ *             networking traffic statistics as it provides a global socket
+ *             identifier that can be assumed unique.
  *     Return
  *             A 8-byte long non-decreasing number on success, or 0 if the
  *             socket field is missing inside *skb*.
index 4941628..5ec88e7 100644 (file)
@@ -16,6 +16,7 @@
 #define CAPI_MSG_BASELEN               8
 #define CAPI_DATA_B3_REQ_LEN           (CAPI_MSG_BASELEN+4+4+2+2+2)
 #define CAPI_DATA_B3_RESP_LEN          (CAPI_MSG_BASELEN+4+2)
+#define CAPI_DISCONNECT_B3_RESP_LEN    (CAPI_MSG_BASELEN+4)
 
 /*----- CAPI commands -----*/
 #define CAPI_ALERT                 0x01
index a18b719..784ba0b 100644 (file)
 
 #define JFFS2_ACL_VERSION              0x0001
 
-// Maybe later...
-//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
-//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
-
-
 #define JFFS2_INO_FLAG_PREREAD   1     /* Do read_inode() for this one at
                                           mount time, don't wait for it to
                                           happen later */
index 6d11286..05669c8 100644 (file)
@@ -31,6 +31,7 @@
 #define KEXEC_ARCH_DEFAULT ( 0 << 16)
 #define KEXEC_ARCH_386     ( 3 << 16)
 #define KEXEC_ARCH_68K     ( 4 << 16)
+#define KEXEC_ARCH_PARISC  (15 << 16)
 #define KEXEC_ARCH_X86_64  (62 << 16)
 #define KEXEC_ARCH_PPC     (20 << 16)
 #define KEXEC_ARCH_PPC64   (21 << 16)
index 5c8a4d7..b5123ab 100644 (file)
@@ -11,4 +11,9 @@ struct xt_nfacct_match_info {
        struct nf_acct  *nfacct;
 };
 
+struct xt_nfacct_match_info_v1 {
+       char            name[NFACCT_NAME_MAX];
+       struct nf_acct  *nfacct __attribute__((aligned(8)));
+};
+
 #endif /* _XT_NFACCT_MATCH_H */
index 094bb03..2e927b3 100644 (file)
@@ -229,4 +229,9 @@ struct prctl_mm_map {
 # define PR_PAC_APDBKEY                        (1UL << 3)
 # define PR_PAC_APGAKEY                        (1UL << 4)
 
+/* Tagged user address controls for arm64 */
+#define PR_SET_TAGGED_ADDR_CTRL                55
+#define PR_GET_TAGGED_ADDR_CTRL                56
+# define PR_TAGGED_ADDR_ENABLE         (1UL << 0)
+
 #endif /* _LINUX_PRCTL_H */
index fd6b5f6..cba368e 100644 (file)
@@ -250,6 +250,7 @@ struct rds_info_rdma_connection {
        __u32           rdma_mr_max;
        __u32           rdma_mr_size;
        __u8            tos;
+       __u8            sl;
        __u32           cache_allocs;
 };
 
@@ -265,6 +266,7 @@ struct rds6_info_rdma_connection {
        __u32           rdma_mr_max;
        __u32           rdma_mr_size;
        __u8            tos;
+       __u8            sl;
        __u32           cache_allocs;
 };
 
index ac49a22..85b809f 100644 (file)
@@ -17,6 +17,7 @@
 #define P_ALL          0
 #define P_PID          1
 #define P_PGID         2
+#define P_PIDFD                3
 
 
 #endif /* _UAPI_LINUX_WAIT_H */
index 7de68f1..af735f5 100644 (file)
@@ -180,6 +180,7 @@ struct siw_cqe {
  * to control CQ arming.
  */
 struct siw_cq_ctrl {
-       __aligned_u64 notify;
+       __u32 flags;
+       __u32 pad;
 };
 #endif
index bd7d650..d96127e 100644 (file)
@@ -30,6 +30,9 @@ config CC_CAN_LINK
 config CC_HAS_ASM_GOTO
        def_bool $(success,$(srctree)/scripts/gcc-goto.sh $(CC))
 
+config TOOLS_SUPPORT_RELR
+       def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
+
 config CC_HAS_WARN_MAYBE_UNINITIALIZED
        def_bool $(cc-option,-Wmaybe-uninitialized)
        help
index 0fcf8e7..5766c61 100644 (file)
@@ -276,29 +276,7 @@ static inline int compat_ipc_parse_version(int *cmd)
        *cmd &= ~IPC_64;
        return version;
 }
-#endif
 
-/* for __ARCH_WANT_SYS_IPC */
-long ksys_semtimedop(int semid, struct sembuf __user *tsops,
-                    unsigned int nsops,
-                    const struct __kernel_timespec __user *timeout);
-long ksys_semget(key_t key, int nsems, int semflg);
-long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg);
-long ksys_msgget(key_t key, int msgflg);
-long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
-long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
-                long msgtyp, int msgflg);
-long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
-                int msgflg);
-long ksys_shmget(key_t key, size_t size, int shmflg);
-long ksys_shmdt(char __user *shmaddr);
-long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
-
-/* for CONFIG_ARCH_WANT_OLD_COMPAT_IPC */
-long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
-                           unsigned int nsops,
-                           const struct old_timespec32 __user *timeout);
-#ifdef CONFIG_COMPAT
 long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg);
 long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr);
 long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
@@ -306,6 +284,7 @@ long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
 long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
                       compat_ssize_t msgsz, int msgflg);
 long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr);
-#endif /* CONFIG_COMPAT */
+
+#endif
 
 #endif
index ef0d95a..48c5376 100644 (file)
@@ -64,6 +64,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o
 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
+obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_CGROUPS) += cgroup/
index 8191a7d..66088a9 100644 (file)
@@ -890,7 +890,8 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
 
 static int bpf_jit_blind_insn(const struct bpf_insn *from,
                              const struct bpf_insn *aux,
-                             struct bpf_insn *to_buff)
+                             struct bpf_insn *to_buff,
+                             bool emit_zext)
 {
        struct bpf_insn *to = to_buff;
        u32 imm_rnd = get_random_int();
@@ -1005,6 +1006,8 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from,
        case 0: /* Part 2 of BPF_LD | BPF_IMM | BPF_DW. */
                *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[0].imm);
                *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
+               if (emit_zext)
+                       *to++ = BPF_ZEXT_REG(BPF_REG_AX);
                *to++ = BPF_ALU64_REG(BPF_OR,  aux[0].dst_reg, BPF_REG_AX);
                break;
 
@@ -1088,7 +1091,8 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
                    insn[1].code == 0)
                        memcpy(aux, insn, sizeof(aux));
 
-               rewritten = bpf_jit_blind_insn(insn, aux, insn_buff);
+               rewritten = bpf_jit_blind_insn(insn, aux, insn_buff,
+                                               clone->aux->verifier_zext);
                if (!rewritten)
                        continue;
 
index 5d141f1..272071e 100644 (file)
@@ -1707,20 +1707,26 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
        if (err)
                goto free_used_maps;
 
-       err = bpf_prog_new_fd(prog);
-       if (err < 0) {
-               /* failed to allocate fd.
-                * bpf_prog_put() is needed because the above
-                * bpf_prog_alloc_id() has published the prog
-                * to the userspace and the userspace may
-                * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
-                */
-               bpf_prog_put(prog);
-               return err;
-       }
-
+       /* Upon success of bpf_prog_alloc_id(), the BPF prog is
+        * effectively publicly exposed. However, retrieving via
+        * bpf_prog_get_fd_by_id() will take another reference,
+        * therefore it cannot be gone underneath us.
+        *
+        * Only for the time /after/ successful bpf_prog_new_fd()
+        * and before returning to userspace, we might just hold
+        * one reference and any parallel close on that fd could
+        * rip everything out. Hence, below notifications must
+        * happen before bpf_prog_new_fd().
+        *
+        * Also, any failure handling from this point onwards must
+        * be using bpf_prog_put() given the program is exposed.
+        */
        bpf_prog_kallsyms_add(prog);
        perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
+
+       err = bpf_prog_new_fd(prog);
+       if (err < 0)
+               bpf_prog_put(prog);
        return err;
 
 free_used_maps:
index c84d83f..c36a719 100644 (file)
@@ -985,9 +985,6 @@ static void __mark_reg_unbounded(struct bpf_reg_state *reg)
        reg->smax_value = S64_MAX;
        reg->umin_value = 0;
        reg->umax_value = U64_MAX;
-
-       /* constant backtracking is enabled for root only for now */
-       reg->precise = capable(CAP_SYS_ADMIN) ? false : true;
 }
 
 /* Mark a register as having a completely unknown (scalar) value. */
@@ -1014,7 +1011,11 @@ static void mark_reg_unknown(struct bpf_verifier_env *env,
                        __mark_reg_not_init(regs + regno);
                return;
        }
-       __mark_reg_unknown(regs + regno);
+       regs += regno;
+       __mark_reg_unknown(regs);
+       /* constant backtracking is enabled for root without bpf2bpf calls */
+       regs->precise = env->subprog_cnt > 1 || !env->allow_ptr_leaks ?
+                       true : false;
 }
 
 static void __mark_reg_not_init(struct bpf_reg_state *reg)
@@ -1771,16 +1772,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno,
                bitmap_from_u64(mask, stack_mask);
                for_each_set_bit(i, mask, 64) {
                        if (i >= func->allocated_stack / BPF_REG_SIZE) {
-                               /* This can happen if backtracking
-                                * is propagating stack precision where
-                                * caller has larger stack frame
-                                * than callee, but backtrack_insn() should
-                                * have returned -ENOTSUPP.
+                               /* the sequence of instructions:
+                                * 2: (bf) r3 = r10
+                                * 3: (7b) *(u64 *)(r3 -8) = r0
+                                * 4: (79) r4 = *(u64 *)(r10 -8)
+                                * doesn't contain jmps. It's backtracked
+                                * as a single block.
+                                * During backtracking insn 3 is not recognized as
+                                * stack access, so at the end of backtracking
+                                * stack slot fp-8 is still marked in stack_mask.
+                                * However the parent state may not have accessed
+                                * fp-8 and it's "unallocated" stack space.
+                                * In such case fallback to conservative.
                                 */
-                               verbose(env, "BUG spi %d stack_size %d\n",
-                                       i, func->allocated_stack);
-                               WARN_ONCE(1, "verifier backtracking bug");
-                               return -EFAULT;
+                               mark_all_scalars_precise(env, st);
+                               return 0;
                        }
 
                        if (func->stack[i].slot_type[0] != STACK_SPILL) {
index 753afbc..8be1da1 100644 (file)
@@ -5255,8 +5255,16 @@ static struct cgroup *cgroup_create(struct cgroup *parent)
         * if the parent has to be frozen, the child has too.
         */
        cgrp->freezer.e_freeze = parent->freezer.e_freeze;
-       if (cgrp->freezer.e_freeze)
+       if (cgrp->freezer.e_freeze) {
+               /*
+                * Set the CGRP_FREEZE flag, so when a process will be
+                * attached to the child cgroup, it will become frozen.
+                * At this point the new cgroup is unpopulated, so we can
+                * consider it frozen immediately.
+                */
+               set_bit(CGRP_FREEZE, &cgrp->flags);
                set_bit(CGRP_FROZEN, &cgrp->flags);
+       }
 
        spin_lock_irq(&css_set_lock);
        for (tcgrp = cgrp; tcgrp; tcgrp = cgroup_parent(tcgrp)) {
index b062425..c09ea4c 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * kernel/configs.c
  * Echo the kernel .config file used to build the kernel
@@ -6,21 +7,6 @@
  * Copyright (C) 2002 Randy Dunlap <rdunlap@xenotime.net>
  * Copyright (C) 2002 Al Stone <ahs3@fc.hp.com>
  * Copyright (C) 2002 Hewlett-Packard Company
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
index 2bd410f..69cfb43 100644 (file)
@@ -230,9 +230,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
  */
 struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
 {
-       int node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
-       size_t count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       size_t align = get_order(PAGE_ALIGN(size));
+       size_t count = size >> PAGE_SHIFT;
        struct page *page = NULL;
        struct cma *cma = NULL;
 
@@ -243,14 +241,12 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
 
        /* CMA can be used only in the context which permits sleeping */
        if (cma && gfpflags_allow_blocking(gfp)) {
+               size_t align = get_order(size);
                size_t cma_align = min_t(size_t, align, CONFIG_CMA_ALIGNMENT);
 
                page = cma_alloc(cma, count, cma_align, gfp & __GFP_NOWARN);
        }
 
-       /* Fallback allocation of normal pages */
-       if (!page)
-               page = alloc_pages_node(node, gfp, align);
        return page;
 }
 
index 59bdcee..8402b29 100644 (file)
@@ -47,9 +47,6 @@ u64 dma_direct_get_required_mask(struct device *dev)
 {
        u64 max_dma = phys_to_dma_direct(dev, (max_pfn - 1) << PAGE_SHIFT);
 
-       if (dev->bus_dma_mask && dev->bus_dma_mask < max_dma)
-               max_dma = dev->bus_dma_mask;
-
        return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
 }
 
@@ -88,6 +85,8 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
 struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
+       size_t alloc_size = PAGE_ALIGN(size);
+       int node = dev_to_node(dev);
        struct page *page = NULL;
        u64 phys_mask;
 
@@ -98,8 +97,14 @@ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
        gfp &= ~__GFP_ZERO;
        gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
                        &phys_mask);
+       page = dma_alloc_contiguous(dev, alloc_size, gfp);
+       if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+               dma_free_contiguous(dev, page, alloc_size);
+               page = NULL;
+       }
 again:
-       page = dma_alloc_contiguous(dev, size, gfp);
+       if (!page)
+               page = alloc_pages_node(node, gfp, get_order(alloc_size));
        if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
                dma_free_contiguous(dev, page, size);
                page = NULL;
@@ -130,10 +135,12 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
        if (!page)
                return NULL;
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+       if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) &&
+           !force_dma_unencrypted(dev)) {
                /* remove any dirty cache lines on the kernel alias */
                if (!PageHighMem(page))
                        arch_dma_prep_coherent(page, size);
+               *dma_handle = phys_to_dma(dev, page_to_phys(page));
                /* return the page pointer as the opaque cookie */
                return page;
        }
@@ -178,7 +185,8 @@ void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
 {
        unsigned int page_order = get_order(size);
 
-       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+       if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) &&
+           !force_dma_unencrypted(dev)) {
                /* cpu_addr is a struct page cookie, not a kernel address */
                __dma_direct_free_pages(dev, size, cpu_addr);
                return;
@@ -297,7 +305,7 @@ void dma_direct_unmap_page(struct device *dev, dma_addr_t addr,
                dma_direct_sync_single_for_cpu(dev, addr, size, dir);
 
        if (unlikely(is_swiotlb_buffer(phys)))
-               swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs);
+               swiotlb_tbl_unmap_single(dev, phys, size, size, dir, attrs);
 }
 EXPORT_SYMBOL(dma_direct_unmap_page);
 
index b945239..b0038ca 100644 (file)
@@ -150,6 +150,23 @@ int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt,
 }
 EXPORT_SYMBOL(dma_get_sgtable_attrs);
 
+#ifdef CONFIG_MMU
+/*
+ * Return the page attributes used for mapping dma_alloc_* memory, either in
+ * kernel space if remapping is needed, or to userspace through dma_mmap_*.
+ */
+pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs)
+{
+       if (dev_is_dma_coherent(dev) ||
+           (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) &&
+             (attrs & DMA_ATTR_NON_CONSISTENT)))
+               return prot;
+       if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_MMAP_PGPROT))
+               return arch_dma_mmap_pgprot(dev, prot, attrs);
+       return pgprot_noncached(prot);
+}
+#endif /* CONFIG_MMU */
+
 /*
  * Create userspace mapping for the DMA-coherent memory.
  */
@@ -164,7 +181,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
        unsigned long pfn;
        int ret = -ENXIO;
 
-       vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs);
+       vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
 
        if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
index a594aec..ffe78f0 100644 (file)
@@ -218,7 +218,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 
        /* create a coherent mapping */
        ret = dma_common_contiguous_remap(page, size, VM_USERMAP,
-                       arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs),
+                       dma_pgprot(dev, PAGE_KERNEL, attrs),
                        __builtin_return_address(0));
        if (!ret) {
                __dma_direct_free_pages(dev, size, page);
index 9de2322..796a44f 100644 (file)
@@ -444,7 +444,9 @@ static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr,
 
 phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
                                   dma_addr_t tbl_dma_addr,
-                                  phys_addr_t orig_addr, size_t size,
+                                  phys_addr_t orig_addr,
+                                  size_t mapping_size,
+                                  size_t alloc_size,
                                   enum dma_data_direction dir,
                                   unsigned long attrs)
 {
@@ -464,6 +466,12 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
                pr_warn_once("%s is active and system is using DMA bounce buffers\n",
                             sme_active() ? "SME" : "SEV");
 
+       if (mapping_size > alloc_size) {
+               dev_warn_once(hwdev, "Invalid sizes (mapping: %zd bytes, alloc: %zd bytes)",
+                             mapping_size, alloc_size);
+               return (phys_addr_t)DMA_MAPPING_ERROR;
+       }
+
        mask = dma_get_seg_boundary(hwdev);
 
        tbl_dma_addr &= mask;
@@ -471,8 +479,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
        offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 
        /*
-        * Carefully handle integer overflow which can occur when mask == ~0UL.
-        */
+        * Carefully handle integer overflow which can occur when mask == ~0UL.
+        */
        max_slots = mask + 1
                    ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
                    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
@@ -481,8 +489,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
         * For mappings greater than or equal to a page, we limit the stride
         * (and hence alignment) to a page size.
         */
-       nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-       if (size >= PAGE_SIZE)
+       nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       if (alloc_size >= PAGE_SIZE)
                stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
        else
                stride = 1;
@@ -547,7 +555,7 @@ not_found:
        spin_unlock_irqrestore(&io_tlb_lock, flags);
        if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
                dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
-                        size, io_tlb_nslabs, tmp_io_tlb_used);
+                        alloc_size, io_tlb_nslabs, tmp_io_tlb_used);
        return (phys_addr_t)DMA_MAPPING_ERROR;
 found:
        io_tlb_used += nslots;
@@ -562,7 +570,7 @@ found:
                io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
            (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE);
+               swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
 
        return tlb_addr;
 }
@@ -571,11 +579,11 @@ found:
  * tlb_addr is the physical address of the bounce buffer to unmap.
  */
 void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
-                             size_t size, enum dma_data_direction dir,
-                             unsigned long attrs)
+                             size_t mapping_size, size_t alloc_size,
+                             enum dma_data_direction dir, unsigned long attrs)
 {
        unsigned long flags;
-       int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       int i, count, nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
        int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
        phys_addr_t orig_addr = io_tlb_orig_addr[index];
 
@@ -585,7 +593,7 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
        if (orig_addr != INVALID_PHYS_ADDR &&
            !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
            ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
-               swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE);
+               swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_FROM_DEVICE);
 
        /*
         * Return the buffer to the free list by setting the corresponding
@@ -665,14 +673,14 @@ bool swiotlb_map(struct device *dev, phys_addr_t *phys, dma_addr_t *dma_addr,
 
        /* Oh well, have to allocate and map a bounce buffer. */
        *phys = swiotlb_tbl_map_single(dev, __phys_to_dma(dev, io_tlb_start),
-                       *phys, size, dir, attrs);
+                       *phys, size, size, dir, attrs);
        if (*phys == (phys_addr_t)DMA_MAPPING_ERROR)
                return false;
 
        /* Ensure that the address returned is DMA'ble */
        *dma_addr = __phys_to_dma(dev, *phys);
        if (unlikely(!dma_capable(dev, *dma_addr, size))) {
-               swiotlb_tbl_unmap_single(dev, *phys, size, dir,
+               swiotlb_tbl_unmap_single(dev, *phys, size, size, dir,
                        attrs | DMA_ATTR_SKIP_CPU_SYNC);
                return false;
        }
index c5cd852..3cc8416 100644 (file)
@@ -413,7 +413,7 @@ static int hw_breakpoint_parse(struct perf_event *bp,
 
 int register_perf_hw_breakpoint(struct perf_event *bp)
 {
-       struct arch_hw_breakpoint hw;
+       struct arch_hw_breakpoint hw = { };
        int err;
 
        err = reserve_bp_slot(bp);
@@ -461,7 +461,7 @@ int
 modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr,
                                bool check)
 {
-       struct arch_hw_breakpoint hw;
+       struct arch_hw_breakpoint hw = { };
        int err;
 
        err = hw_breakpoint_parse(bp, attr, &hw);
index 5b4a5dc..22ab6a4 100644 (file)
@@ -1554,6 +1554,23 @@ end:
        return retval;
 }
 
+static struct pid *pidfd_get_pid(unsigned int fd)
+{
+       struct fd f;
+       struct pid *pid;
+
+       f = fdget(fd);
+       if (!f.file)
+               return ERR_PTR(-EBADF);
+
+       pid = pidfd_pid(f.file);
+       if (!IS_ERR(pid))
+               get_pid(pid);
+
+       fdput(f);
+       return pid;
+}
+
 static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
                          int options, struct rusage *ru)
 {
@@ -1576,19 +1593,32 @@ static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
                type = PIDTYPE_PID;
                if (upid <= 0)
                        return -EINVAL;
+
+               pid = find_get_pid(upid);
                break;
        case P_PGID:
                type = PIDTYPE_PGID;
-               if (upid <= 0)
+               if (upid < 0)
+                       return -EINVAL;
+
+               if (upid)
+                       pid = find_get_pid(upid);
+               else
+                       pid = get_task_pid(current, PIDTYPE_PGID);
+               break;
+       case P_PIDFD:
+               type = PIDTYPE_PID;
+               if (upid < 0)
                        return -EINVAL;
+
+               pid = pidfd_get_pid(upid);
+               if (IS_ERR(pid))
+                       return PTR_ERR(pid);
                break;
        default:
                return -EINVAL;
        }
 
-       if (type < PIDTYPE_MAX)
-               pid = find_get_pid(upid);
-
        wo.wo_type      = type;
        wo.wo_pid       = pid;
        wo.wo_flags     = options;
index 2852d0e..1d1cd06 100644 (file)
@@ -768,6 +768,7 @@ static void set_max_threads(unsigned int max_threads_suggested)
 int arch_task_struct_size __read_mostly;
 #endif
 
+#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
 static void task_struct_whitelist(unsigned long *offset, unsigned long *size)
 {
        /* Fetch thread_struct whitelist for the architecture. */
@@ -782,6 +783,7 @@ static void task_struct_whitelist(unsigned long *offset, unsigned long *size)
        else
                *offset += offsetof(struct task_struct, thread);
 }
+#endif /* CONFIG_ARCH_TASK_STRUCT_ALLOCATOR */
 
 void __init fork_init(void)
 {
@@ -1690,6 +1692,14 @@ static inline void rcu_copy_process(struct task_struct *p)
 #endif /* #ifdef CONFIG_TASKS_RCU */
 }
 
+struct pid *pidfd_pid(const struct file *file)
+{
+       if (file->f_op == &pidfd_fops)
+               return file->private_data;
+
+       return ERR_PTR(-EBADF);
+}
+
 static int pidfd_release(struct inode *inode, struct file *file)
 {
        struct pid *pid = file->private_data;
@@ -2338,6 +2348,8 @@ struct mm_struct *copy_init_mm(void)
  *
  * It copies the process, and if successful kick-starts
  * it and waits for it to finish using the VM if required.
+ *
+ * args->exit_signal is expected to be checked for sanity by the caller.
  */
 long _do_fork(struct kernel_clone_args *args)
 {
@@ -2562,6 +2574,14 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
        if (copy_from_user(&args, uargs, size))
                return -EFAULT;
 
+       /*
+        * Verify that higher 32bits of exit_signal are unset and that
+        * it is a valid signal
+        */
+       if (unlikely((args.exit_signal & ~((u64)CSIGNAL)) ||
+                    !valid_signal(args.exit_signal)))
+               return -EINVAL;
+
        *kargs = (struct kernel_clone_args){
                .flags          = args.flags,
                .pidfd          = u64_to_user_ptr(args.pidfd),
index 9484e88..9be995f 100644 (file)
@@ -295,6 +295,18 @@ static void irq_sysfs_add(int irq, struct irq_desc *desc)
        }
 }
 
+static void irq_sysfs_del(struct irq_desc *desc)
+{
+       /*
+        * If irq_sysfs_init() has not yet been invoked (early boot), then
+        * irq_kobj_base is NULL and the descriptor was never added.
+        * kobject_del() complains about a object with no parent, so make
+        * it conditional.
+        */
+       if (irq_kobj_base)
+               kobject_del(&desc->kobj);
+}
+
 static int __init irq_sysfs_init(void)
 {
        struct irq_desc *desc;
@@ -325,6 +337,7 @@ static struct kobj_type irq_kobj_type = {
 };
 
 static void irq_sysfs_add(int irq, struct irq_desc *desc) {}
+static void irq_sysfs_del(struct irq_desc *desc) {}
 
 #endif /* CONFIG_SYSFS */
 
@@ -438,7 +451,7 @@ static void free_desc(unsigned int irq)
         * The sysfs entry must be serialized against a concurrent
         * irq_sysfs_init() as well.
         */
-       kobject_del(&desc->kobj);
+       irq_sysfs_del(desc);
        delete_irq_desc(irq);
 
        /*
index da9addb..cfc4f08 100644 (file)
@@ -100,10 +100,6 @@ static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
        return 0;
 }
 
-#ifndef is_affinity_mask_valid
-#define is_affinity_mask_valid(val) 1
-#endif
-
 int no_irq_affinity;
 static int irq_affinity_proc_show(struct seq_file *m, void *v)
 {
@@ -136,11 +132,6 @@ static ssize_t write_irq_affinity(int type, struct file *file,
        if (err)
                goto free_cpumask;
 
-       if (!is_affinity_mask_valid(new_value)) {
-               err = -EINVAL;
-               goto free_cpumask;
-       }
-
        /*
         * Do not allow disabling IRQs completely - it's a too easy
         * way to make the system unusable accidentally :-) At least
@@ -232,11 +223,6 @@ static ssize_t default_affinity_write(struct file *file,
        if (err)
                goto out;
 
-       if (!is_affinity_mask_valid(new_value)) {
-               err = -EINVAL;
-               goto out;
-       }
-
        /*
         * Do not allow disabling IRQs completely - it's a too easy
         * way to make the system unusable accidentally :-) At least
index 95414ad..98c04ca 100644 (file)
@@ -36,6 +36,8 @@ static void resend_irqs(unsigned long arg)
                irq = find_first_bit(irqs_resend, nr_irqs);
                clear_bit(irq, irqs_resend);
                desc = irq_to_desc(irq);
+               if (!desc)
+                       continue;
                local_irq_disable();
                desc->handle_irq(desc);
                local_irq_enable();
index df30084..cdb3ffa 100644 (file)
@@ -407,7 +407,9 @@ static bool jump_label_can_update(struct jump_entry *entry, bool init)
                return false;
 
        if (!kernel_text_address(jump_entry_code(entry))) {
-               WARN_ONCE(1, "can't patch jump_label at %pS", (void *)jump_entry_code(entry));
+               WARN_ONCE(!jump_entry_is_init(entry),
+                         "can't patch jump_label at %pS",
+                         (void *)jump_entry_code(entry));
                return false;
        }
 
index 95a260f..136ce04 100644 (file)
@@ -263,8 +263,10 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 {
        char namebuf[KSYM_NAME_LEN];
 
-       if (is_ksym_addr(addr))
-               return !!get_symbol_pos(addr, symbolsize, offset);
+       if (is_ksym_addr(addr)) {
+               get_symbol_pos(addr, symbolsize, offset);
+               return 1;
+       }
        return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) ||
               !!__bpf_address_lookup(addr, symbolsize, offset, namebuf);
 }
diff --git a/kernel/kexec_elf.c b/kernel/kexec_elf.c
new file mode 100644 (file)
index 0000000..d368963
--- /dev/null
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Load ELF vmlinux file for the kexec_file_load syscall.
+ *
+ * Copyright (C) 2004  Adam Litke (agl@us.ibm.com)
+ * Copyright (C) 2004  IBM Corp.
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com)
+ * Copyright (C) 2006  Mohan Kumar M (mohan@in.ibm.com)
+ * Copyright (C) 2016  IBM Corporation
+ *
+ * Based on kexec-tools' kexec-elf-exec.c and kexec-elf-ppc64.c.
+ * Heavily modified for the kernel by
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>.
+ */
+
+#define pr_fmt(fmt)    "kexec_elf: " fmt
+
+#include <linux/elf.h>
+#include <linux/kexec.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
+{
+       return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
+}
+
+static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value)
+{
+       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+               value = le64_to_cpu(value);
+       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+               value = be64_to_cpu(value);
+
+       return value;
+}
+
+static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value)
+{
+       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+               value = le32_to_cpu(value);
+       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+               value = be32_to_cpu(value);
+
+       return value;
+}
+
+static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value)
+{
+       if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+               value = le16_to_cpu(value);
+       else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+               value = be16_to_cpu(value);
+
+       return value;
+}
+
+/**
+ * elf_is_ehdr_sane - check that it is safe to use the ELF header
+ * @buf_len:   size of the buffer in which the ELF file is loaded.
+ */
+static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len)
+{
+       if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) {
+               pr_debug("Bad program header size.\n");
+               return false;
+       } else if (ehdr->e_shnum > 0 &&
+                  ehdr->e_shentsize != sizeof(struct elf_shdr)) {
+               pr_debug("Bad section header size.\n");
+               return false;
+       } else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
+                  ehdr->e_version != EV_CURRENT) {
+               pr_debug("Unknown ELF version.\n");
+               return false;
+       }
+
+       if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
+               size_t phdr_size;
+
+               /*
+                * e_phnum is at most 65535 so calculating the size of the
+                * program header cannot overflow.
+                */
+               phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
+
+               /* Sanity check the program header table location. */
+               if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) {
+                       pr_debug("Program headers at invalid location.\n");
+                       return false;
+               } else if (ehdr->e_phoff + phdr_size > buf_len) {
+                       pr_debug("Program headers truncated.\n");
+                       return false;
+               }
+       }
+
+       if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
+               size_t shdr_size;
+
+               /*
+                * e_shnum is at most 65536 so calculating
+                * the size of the section header cannot overflow.
+                */
+               shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum;
+
+               /* Sanity check the section header table location. */
+               if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) {
+                       pr_debug("Section headers at invalid location.\n");
+                       return false;
+               } else if (ehdr->e_shoff + shdr_size > buf_len) {
+                       pr_debug("Section headers truncated.\n");
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
+{
+       struct elfhdr *buf_ehdr;
+
+       if (len < sizeof(*buf_ehdr)) {
+               pr_debug("Buffer is too small to hold ELF header.\n");
+               return -ENOEXEC;
+       }
+
+       memset(ehdr, 0, sizeof(*ehdr));
+       memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident));
+       if (!elf_is_elf_file(ehdr)) {
+               pr_debug("No ELF header magic.\n");
+               return -ENOEXEC;
+       }
+
+       if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
+               pr_debug("Not a supported ELF class.\n");
+               return -ENOEXEC;
+       } else  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
+               ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+               pr_debug("Not a supported ELF data format.\n");
+               return -ENOEXEC;
+       }
+
+       buf_ehdr = (struct elfhdr *) buf;
+       if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) {
+               pr_debug("Bad ELF header size.\n");
+               return -ENOEXEC;
+       }
+
+       ehdr->e_type      = elf16_to_cpu(ehdr, buf_ehdr->e_type);
+       ehdr->e_machine   = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
+       ehdr->e_version   = elf32_to_cpu(ehdr, buf_ehdr->e_version);
+       ehdr->e_flags     = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
+       ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
+       ehdr->e_phnum     = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
+       ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize);
+       ehdr->e_shnum     = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
+       ehdr->e_shstrndx  = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
+
+       switch (ehdr->e_ident[EI_CLASS]) {
+       case ELFCLASS64:
+               ehdr->e_entry = elf64_to_cpu(ehdr, buf_ehdr->e_entry);
+               ehdr->e_phoff = elf64_to_cpu(ehdr, buf_ehdr->e_phoff);
+               ehdr->e_shoff = elf64_to_cpu(ehdr, buf_ehdr->e_shoff);
+               break;
+
+       case ELFCLASS32:
+               ehdr->e_entry = elf32_to_cpu(ehdr, buf_ehdr->e_entry);
+               ehdr->e_phoff = elf32_to_cpu(ehdr, buf_ehdr->e_phoff);
+               ehdr->e_shoff = elf32_to_cpu(ehdr, buf_ehdr->e_shoff);
+               break;
+
+       default:
+               pr_debug("Unknown ELF class.\n");
+               return -EINVAL;
+       }
+
+       return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
+}
+
+/**
+ * elf_is_phdr_sane - check that it is safe to use the program header
+ * @buf_len:   size of the buffer in which the ELF file is loaded.
+ */
+static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len)
+{
+
+       if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) {
+               pr_debug("ELF segment location wraps around.\n");
+               return false;
+       } else if (phdr->p_offset + phdr->p_filesz > buf_len) {
+               pr_debug("ELF segment not in file.\n");
+               return false;
+       } else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) {
+               pr_debug("ELF segment address wraps around.\n");
+               return false;
+       }
+
+       return true;
+}
+
+static int elf_read_phdr(const char *buf, size_t len,
+                        struct kexec_elf_info *elf_info,
+                        int idx)
+{
+       /* Override the const in proghdrs, we are the ones doing the loading. */
+       struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
+       const struct elfhdr *ehdr = elf_info->ehdr;
+       const char *pbuf;
+       struct elf_phdr *buf_phdr;
+
+       pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr));
+       buf_phdr = (struct elf_phdr *) pbuf;
+
+       phdr->p_type   = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
+       phdr->p_flags  = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
+
+       switch (ehdr->e_ident[EI_CLASS]) {
+       case ELFCLASS64:
+               phdr->p_offset = elf64_to_cpu(ehdr, buf_phdr->p_offset);
+               phdr->p_paddr  = elf64_to_cpu(ehdr, buf_phdr->p_paddr);
+               phdr->p_vaddr  = elf64_to_cpu(ehdr, buf_phdr->p_vaddr);
+               phdr->p_filesz = elf64_to_cpu(ehdr, buf_phdr->p_filesz);
+               phdr->p_memsz  = elf64_to_cpu(ehdr, buf_phdr->p_memsz);
+               phdr->p_align  = elf64_to_cpu(ehdr, buf_phdr->p_align);
+               break;
+
+       case ELFCLASS32:
+               phdr->p_offset = elf32_to_cpu(ehdr, buf_phdr->p_offset);
+               phdr->p_paddr  = elf32_to_cpu(ehdr, buf_phdr->p_paddr);
+               phdr->p_vaddr  = elf32_to_cpu(ehdr, buf_phdr->p_vaddr);
+               phdr->p_filesz = elf32_to_cpu(ehdr, buf_phdr->p_filesz);
+               phdr->p_memsz  = elf32_to_cpu(ehdr, buf_phdr->p_memsz);
+               phdr->p_align  = elf32_to_cpu(ehdr, buf_phdr->p_align);
+               break;
+
+       default:
+               pr_debug("Unknown ELF class.\n");
+               return -EINVAL;
+       }
+
+       return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
+}
+
+/**
+ * elf_read_phdrs - read the program headers from the buffer
+ *
+ * This function assumes that the program header table was checked for sanity.
+ * Use elf_is_ehdr_sane() if it wasn't.
+ */
+static int elf_read_phdrs(const char *buf, size_t len,
+                         struct kexec_elf_info *elf_info)
+{
+       size_t phdr_size, i;
+       const struct elfhdr *ehdr = elf_info->ehdr;
+
+       /*
+        * e_phnum is at most 65535 so calculating the size of the
+        * program header cannot overflow.
+        */
+       phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
+
+       elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL);
+       if (!elf_info->proghdrs)
+               return -ENOMEM;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               int ret;
+
+               ret = elf_read_phdr(buf, len, elf_info, i);
+               if (ret) {
+                       kfree(elf_info->proghdrs);
+                       elf_info->proghdrs = NULL;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info
+ * @buf:       Buffer to read ELF file from.
+ * @len:       Size of @buf.
+ * @ehdr:      Pointer to existing struct which will be populated.
+ * @elf_info:  Pointer to existing struct which will be populated.
+ *
+ * This function allows reading ELF files with different byte order than
+ * the kernel, byte-swapping the fields as needed.
+ *
+ * Return:
+ * On success returns 0, and the caller should call
+ * kexec_free_elf_info(elf_info) to free the memory allocated for the section
+ * and program headers.
+ */
+static int elf_read_from_buffer(const char *buf, size_t len,
+                               struct elfhdr *ehdr,
+                               struct kexec_elf_info *elf_info)
+{
+       int ret;
+
+       ret = elf_read_ehdr(buf, len, ehdr);
+       if (ret)
+               return ret;
+
+       elf_info->buffer = buf;
+       elf_info->ehdr = ehdr;
+       if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
+               ret = elf_read_phdrs(buf, len, elf_info);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/**
+ * kexec_free_elf_info - free memory allocated by elf_read_from_buffer
+ */
+void kexec_free_elf_info(struct kexec_elf_info *elf_info)
+{
+       kfree(elf_info->proghdrs);
+       memset(elf_info, 0, sizeof(*elf_info));
+}
+/**
+ * kexec_build_elf_info - read ELF executable and check that we can use it
+ */
+int kexec_build_elf_info(const char *buf, size_t len, struct elfhdr *ehdr,
+                              struct kexec_elf_info *elf_info)
+{
+       int i;
+       int ret;
+
+       ret = elf_read_from_buffer(buf, len, ehdr, elf_info);
+       if (ret)
+               return ret;
+
+       /* Big endian vmlinux has type ET_DYN. */
+       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
+               pr_err("Not an ELF executable.\n");
+               goto error;
+       } else if (!elf_info->proghdrs) {
+               pr_err("No ELF program header.\n");
+               goto error;
+       }
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               /*
+                * Kexec does not support loading interpreters.
+                * In addition this check keeps us from attempting
+                * to kexec ordinay executables.
+                */
+               if (elf_info->proghdrs[i].p_type == PT_INTERP) {
+                       pr_err("Requires an ELF interpreter.\n");
+                       goto error;
+               }
+       }
+
+       return 0;
+error:
+       kexec_free_elf_info(elf_info);
+       return -ENOEXEC;
+}
+
+
+int kexec_elf_probe(const char *buf, unsigned long len)
+{
+       struct elfhdr ehdr;
+       struct kexec_elf_info elf_info;
+       int ret;
+
+       ret = kexec_build_elf_info(buf, len, &ehdr, &elf_info);
+       if (ret)
+               return ret;
+
+       kexec_free_elf_info(&elf_info);
+
+       return elf_check_arch(&ehdr) ? 0 : -ENOEXEC;
+}
+
+/**
+ * kexec_elf_load - load ELF executable image
+ * @lowest_load_addr:  On return, will be the address where the first PT_LOAD
+ *                     section will be loaded in memory.
+ *
+ * Return:
+ * 0 on success, negative value on failure.
+ */
+int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
+                        struct kexec_elf_info *elf_info,
+                        struct kexec_buf *kbuf,
+                        unsigned long *lowest_load_addr)
+{
+       unsigned long lowest_addr = UINT_MAX;
+       int ret;
+       size_t i;
+
+       /* Read in the PT_LOAD segments. */
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               unsigned long load_addr;
+               size_t size;
+               const struct elf_phdr *phdr;
+
+               phdr = &elf_info->proghdrs[i];
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               size = phdr->p_filesz;
+               if (size > phdr->p_memsz)
+                       size = phdr->p_memsz;
+
+               kbuf->buffer = (void *) elf_info->buffer + phdr->p_offset;
+               kbuf->bufsz = size;
+               kbuf->memsz = phdr->p_memsz;
+               kbuf->buf_align = phdr->p_align;
+               kbuf->buf_min = phdr->p_paddr;
+               kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
+               ret = kexec_add_buffer(kbuf);
+               if (ret)
+                       goto out;
+               load_addr = kbuf->mem;
+
+               if (load_addr < lowest_addr)
+                       lowest_addr = load_addr;
+       }
+
+       *lowest_load_addr = lowest_addr;
+       ret = 0;
+ out:
+       return ret;
+}
index 9873fc6..d9770a5 100644 (file)
@@ -470,6 +470,7 @@ static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer);
  */
 static void do_optimize_kprobes(void)
 {
+       lockdep_assert_held(&text_mutex);
        /*
         * The optimization/unoptimization refers online_cpus via
         * stop_machine() and cpu-hotplug modifies online_cpus.
@@ -487,9 +488,7 @@ static void do_optimize_kprobes(void)
            list_empty(&optimizing_list))
                return;
 
-       mutex_lock(&text_mutex);
        arch_optimize_kprobes(&optimizing_list);
-       mutex_unlock(&text_mutex);
 }
 
 /*
@@ -500,6 +499,7 @@ static void do_unoptimize_kprobes(void)
 {
        struct optimized_kprobe *op, *tmp;
 
+       lockdep_assert_held(&text_mutex);
        /* See comment in do_optimize_kprobes() */
        lockdep_assert_cpus_held();
 
@@ -507,7 +507,6 @@ static void do_unoptimize_kprobes(void)
        if (list_empty(&unoptimizing_list))
                return;
 
-       mutex_lock(&text_mutex);
        arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
        /* Loop free_list for disarming */
        list_for_each_entry_safe(op, tmp, &freeing_list, list) {
@@ -524,7 +523,6 @@ static void do_unoptimize_kprobes(void)
                } else
                        list_del_init(&op->list);
        }
-       mutex_unlock(&text_mutex);
 }
 
 /* Reclaim all kprobes on the free_list */
@@ -556,6 +554,7 @@ static void kprobe_optimizer(struct work_struct *work)
 {
        mutex_lock(&kprobe_mutex);
        cpus_read_lock();
+       mutex_lock(&text_mutex);
        /* Lock modules while optimizing kprobes */
        mutex_lock(&module_mutex);
 
@@ -583,6 +582,7 @@ static void kprobe_optimizer(struct work_struct *work)
        do_free_cleaned_kprobes();
 
        mutex_unlock(&module_mutex);
+       mutex_unlock(&text_mutex);
        cpus_read_unlock();
        mutex_unlock(&kprobe_mutex);
 
index 5933395..9ee9342 100644 (file)
@@ -65,9 +65,9 @@
 /*
  * Modules' sections will be aligned on page boundaries
  * to ensure complete separation of code and data, but
- * only when CONFIG_STRICT_MODULE_RWX=y
+ * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
  */
-#ifdef CONFIG_STRICT_MODULE_RWX
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
 # define debug_align(X) ALIGN(X, PAGE_SIZE)
 #else
 # define debug_align(X) (X)
index 2b037f1..df9f1fe 100644 (file)
@@ -3904,7 +3904,7 @@ void __noreturn do_task_dead(void)
 
 static inline void sched_submit_work(struct task_struct *tsk)
 {
-       if (!tsk->state || tsk_is_pi_blocked(tsk))
+       if (!tsk->state)
                return;
 
        /*
@@ -3920,6 +3920,9 @@ static inline void sched_submit_work(struct task_struct *tsk)
                preempt_enable_no_resched();
        }
 
+       if (tsk_is_pi_blocked(tsk))
+               return;
+
        /*
         * If we are going to sleep and we have plugged IO queued,
         * make sure to submit it to avoid deadlocks.
@@ -5102,37 +5105,40 @@ out_unlock:
        return retval;
 }
 
-static int sched_read_attr(struct sched_attr __user *uattr,
-                          struct sched_attr *attr,
-                          unsigned int usize)
+/*
+ * Copy the kernel size attribute structure (which might be larger
+ * than what user-space knows about) to user-space.
+ *
+ * Note that all cases are valid: user-space buffer can be larger or
+ * smaller than the kernel-space buffer. The usual case is that both
+ * have the same size.
+ */
+static int
+sched_attr_copy_to_user(struct sched_attr __user *uattr,
+                       struct sched_attr *kattr,
+                       unsigned int usize)
 {
-       int ret;
+       unsigned int ksize = sizeof(*kattr);
 
        if (!access_ok(uattr, usize))
                return -EFAULT;
 
        /*
-        * If we're handed a smaller struct than we know of,
-        * ensure all the unknown bits are 0 - i.e. old
-        * user-space does not get uncomplete information.
+        * sched_getattr() ABI forwards and backwards compatibility:
+        *
+        * If usize == ksize then we just copy everything to user-space and all is good.
+        *
+        * If usize < ksize then we only copy as much as user-space has space for,
+        * this keeps ABI compatibility as well. We skip the rest.
+        *
+        * If usize > ksize then user-space is using a newer version of the ABI,
+        * which part the kernel doesn't know about. Just ignore it - tooling can
+        * detect the kernel's knowledge of attributes from the attr->size value
+        * which is set to ksize in this case.
         */
-       if (usize < sizeof(*attr)) {
-               unsigned char *addr;
-               unsigned char *end;
-
-               addr = (void *)attr + usize;
-               end  = (void *)attr + sizeof(*attr);
+       kattr->size = min(usize, ksize);
 
-               for (; addr < end; addr++) {
-                       if (*addr)
-                               return -EFBIG;
-               }
-
-               attr->size = usize;
-       }
-
-       ret = copy_to_user(uattr, attr, attr->size);
-       if (ret)
+       if (copy_to_user(uattr, kattr, kattr->size))
                return -EFAULT;
 
        return 0;
@@ -5142,20 +5148,18 @@ static int sched_read_attr(struct sched_attr __user *uattr,
  * sys_sched_getattr - similar to sched_getparam, but with sched_attr
  * @pid: the pid in question.
  * @uattr: structure containing the extended parameters.
- * @size: sizeof(attr) for fwd/bwd comp.
+ * @usize: sizeof(attr) that user-space knows about, for forwards and backwards compatibility.
  * @flags: for future extension.
  */
 SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
-               unsigned int, size, unsigned int, flags)
+               unsigned int, usize, unsigned int, flags)
 {
-       struct sched_attr attr = {
-               .size = sizeof(struct sched_attr),
-       };
+       struct sched_attr kattr = { };
        struct task_struct *p;
        int retval;
 
-       if (!uattr || pid < 0 || size > PAGE_SIZE ||
-           size < SCHED_ATTR_SIZE_VER0 || flags)
+       if (!uattr || pid < 0 || usize > PAGE_SIZE ||
+           usize < SCHED_ATTR_SIZE_VER0 || flags)
                return -EINVAL;
 
        rcu_read_lock();
@@ -5168,25 +5172,24 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
        if (retval)
                goto out_unlock;
 
-       attr.sched_policy = p->policy;
+       kattr.sched_policy = p->policy;
        if (p->sched_reset_on_fork)
-               attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
+               kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
        if (task_has_dl_policy(p))
-               __getparam_dl(p, &attr);
+               __getparam_dl(p, &kattr);
        else if (task_has_rt_policy(p))
-               attr.sched_priority = p->rt_priority;
+               kattr.sched_priority = p->rt_priority;
        else
-               attr.sched_nice = task_nice(p);
+               kattr.sched_nice = task_nice(p);
 
 #ifdef CONFIG_UCLAMP_TASK
-       attr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value;
-       attr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value;
+       kattr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value;
+       kattr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value;
 #endif
 
        rcu_read_unlock();
 
-       retval = sched_read_attr(uattr, &attr, size);
-       return retval;
+       return sched_attr_copy_to_user(uattr, &kattr, usize);
 
 out_unlock:
        rcu_read_unlock();
index 636ca6f..867b4bb 100644 (file)
@@ -40,6 +40,7 @@ struct sugov_policy {
        struct task_struct      *thread;
        bool                    work_in_progress;
 
+       bool                    limits_changed;
        bool                    need_freq_update;
 };
 
@@ -89,8 +90,11 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
            !cpufreq_this_cpu_can_update(sg_policy->policy))
                return false;
 
-       if (unlikely(sg_policy->need_freq_update))
+       if (unlikely(sg_policy->limits_changed)) {
+               sg_policy->limits_changed = false;
+               sg_policy->need_freq_update = true;
                return true;
+       }
 
        delta_ns = time - sg_policy->last_freq_update_time;
 
@@ -437,7 +441,7 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; }
 static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu, struct sugov_policy *sg_policy)
 {
        if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl)
-               sg_policy->need_freq_update = true;
+               sg_policy->limits_changed = true;
 }
 
 static void sugov_update_single(struct update_util_data *hook, u64 time,
@@ -457,7 +461,8 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
        if (!sugov_should_update_freq(sg_policy, time))
                return;
 
-       busy = sugov_cpu_is_busy(sg_cpu);
+       /* Limits may have changed, don't skip frequency update */
+       busy = !sg_policy->need_freq_update && sugov_cpu_is_busy(sg_cpu);
 
        util = sugov_get_util(sg_cpu);
        max = sg_cpu->max;
@@ -831,6 +836,7 @@ static int sugov_start(struct cpufreq_policy *policy)
        sg_policy->last_freq_update_time        = 0;
        sg_policy->next_freq                    = 0;
        sg_policy->work_in_progress             = false;
+       sg_policy->limits_changed               = false;
        sg_policy->need_freq_update             = false;
        sg_policy->cached_raw_freq              = 0;
 
@@ -879,7 +885,7 @@ static void sugov_limits(struct cpufreq_policy *policy)
                mutex_unlock(&sg_policy->work_lock);
        }
 
-       sg_policy->need_freq_update = true;
+       sg_policy->limits_changed = true;
 }
 
 struct cpufreq_governor schedutil_gov = {
index bc9cfea..500f5db 100644 (file)
@@ -4470,6 +4470,8 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
        if (likely(cfs_rq->runtime_remaining > 0))
                return;
 
+       if (cfs_rq->throttled)
+               return;
        /*
         * if we're unable to extend our runtime we resched so that the active
         * hierarchy can be throttled
@@ -4673,6 +4675,9 @@ static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
                if (!cfs_rq_throttled(cfs_rq))
                        goto next;
 
+               /* By the above check, this should never be true */
+               SCHED_WARN_ON(cfs_rq->runtime_remaining > 0);
+
                runtime = -cfs_rq->runtime_remaining + 1;
                if (runtime > remaining)
                        runtime = remaining;
index 23fbbcc..6e52b67 100644 (file)
@@ -1131,7 +1131,15 @@ static void psi_trigger_destroy(struct kref *ref)
         * deadlock while waiting for psi_poll_work to acquire trigger_lock
         */
        if (kworker_to_destroy) {
+               /*
+                * After the RCU grace period has expired, the worker
+                * can no longer be found through group->poll_kworker.
+                * But it might have been already scheduled before
+                * that - deschedule it cleanly before destroying it.
+                */
                kthread_cancel_delayed_work_sync(&group->poll_work);
+               atomic_set(&group->poll_scheduled, 0);
+
                kthread_destroy_worker(kworker_to_destroy);
        }
        kfree(t);
index e667be6..c4da1ef 100644 (file)
@@ -90,6 +90,11 @@ static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
            handler == SIG_DFL && !(force && sig_kernel_only(sig)))
                return true;
 
+       /* Only allow kernel generated signals to this kthread */
+       if (unlikely((t->flags & PF_KTHREAD) &&
+                    (handler == SIG_KTHREAD_KERNEL) && !force))
+               return true;
+
        return sig_handler_ignored(handler, sig);
 }
 
@@ -3673,8 +3678,11 @@ static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
 
 static struct pid *pidfd_to_pid(const struct file *file)
 {
-       if (file->f_op == &pidfd_fops)
-               return file->private_data;
+       struct pid *pid;
+
+       pid = pidfd_pid(file);
+       if (!IS_ERR(pid))
+               return pid;
 
        return tgid_pidfd_to_pid(file);
 }
index 2969304..ec48396 100644 (file)
 #ifndef PAC_RESET_KEYS
 # define PAC_RESET_KEYS(a, b)  (-EINVAL)
 #endif
+#ifndef SET_TAGGED_ADDR_CTRL
+# define SET_TAGGED_ADDR_CTRL(a)       (-EINVAL)
+#endif
+#ifndef GET_TAGGED_ADDR_CTRL
+# define GET_TAGGED_ADDR_CTRL()                (-EINVAL)
+#endif
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -2492,6 +2498,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        return -EINVAL;
                error = PAC_RESET_KEYS(me, arg2);
                break;
+       case PR_SET_TAGGED_ADDR_CTRL:
+               if (arg3 || arg4 || arg5)
+                       return -EINVAL;
+               error = SET_TAGGED_ADDR_CTRL(arg2);
+               break;
+       case PR_GET_TAGGED_ADDR_CTRL:
+               if (arg2 || arg3 || arg4 || arg5)
+                       return -EINVAL;
+               error = GET_TAGGED_ADDR_CTRL();
+               break;
        default:
                error = -EINVAL;
                break;
index d911c84..ca69290 100644 (file)
@@ -146,6 +146,11 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
 static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
 {
        tk->offs_boot = ktime_add(tk->offs_boot, delta);
+       /*
+        * Timespec representation for VDSO update to avoid 64bit division
+        * on every update.
+        */
+       tk->monotonic_to_boot = ktime_to_timespec64(tk->offs_boot);
 }
 
 /*
index 8cf3596..4bc37ac 100644 (file)
@@ -17,7 +17,7 @@ static inline void update_vdso_data(struct vdso_data *vdata,
                                    struct timekeeper *tk)
 {
        struct vdso_timestamp *vdso_ts;
-       u64 nsec;
+       u64 nsec, sec;
 
        vdata[CS_HRES_COARSE].cycle_last        = tk->tkr_mono.cycle_last;
        vdata[CS_HRES_COARSE].mask              = tk->tkr_mono.mask;
@@ -45,23 +45,27 @@ static inline void update_vdso_data(struct vdso_data *vdata,
        }
        vdso_ts->nsec   = nsec;
 
-       /* CLOCK_MONOTONIC_RAW */
-       vdso_ts         = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
-       vdso_ts->sec    = tk->raw_sec;
-       vdso_ts->nsec   = tk->tkr_raw.xtime_nsec;
+       /* Copy MONOTONIC time for BOOTTIME */
+       sec     = vdso_ts->sec;
+       /* Add the boot offset */
+       sec     += tk->monotonic_to_boot.tv_sec;
+       nsec    += (u64)tk->monotonic_to_boot.tv_nsec << tk->tkr_mono.shift;
 
        /* CLOCK_BOOTTIME */
        vdso_ts         = &vdata[CS_HRES_COARSE].basetime[CLOCK_BOOTTIME];
-       vdso_ts->sec    = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
-       nsec = tk->tkr_mono.xtime_nsec;
-       nsec += ((u64)(tk->wall_to_monotonic.tv_nsec +
-                      ktime_to_ns(tk->offs_boot)) << tk->tkr_mono.shift);
+       vdso_ts->sec    = sec;
+
        while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
                nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
                vdso_ts->sec++;
        }
        vdso_ts->nsec   = nsec;
 
+       /* CLOCK_MONOTONIC_RAW */
+       vdso_ts         = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
+       vdso_ts->sec    = tk->raw_sec;
+       vdso_ts->nsec   = tk->tkr_raw.xtime_nsec;
+
        /* CLOCK_TAI */
        vdso_ts         = &vdata[CS_HRES_COARSE].basetime[CLOCK_TAI];
        vdso_ts->sec    = tk->xtime_sec + (s64)tk->tai_offset;
index eca3450..f9821a3 100644 (file)
@@ -3095,6 +3095,14 @@ t_probe_next(struct seq_file *m, loff_t *pos)
                hnd = &iter->probe_entry->hlist;
 
        hash = iter->probe->ops.func_hash->filter_hash;
+
+       /*
+        * A probe being registered may temporarily have an empty hash
+        * and it's at the end of the func_probes list.
+        */
+       if (!hash || hash == EMPTY_HASH)
+               return NULL;
+
        size = 1 << hash->size_bits;
 
  retry:
@@ -4320,12 +4328,21 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
 
        mutex_unlock(&ftrace_lock);
 
+       /*
+        * Note, there's a small window here that the func_hash->filter_hash
+        * may be NULL or empty. Need to be carefule when reading the loop.
+        */
        mutex_lock(&probe->ops.func_hash->regex_lock);
 
        orig_hash = &probe->ops.func_hash->filter_hash;
        old_hash = *orig_hash;
        hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
 
+       if (!hash) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        ret = ftrace_match_records(hash, glob, strlen(glob));
 
        /* Nothing found? */
index 525a97f..563e80f 100644 (file)
@@ -1567,9 +1567,9 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu,
 
 /**
  * update_max_tr_single - only copy one trace over, and reset the rest
- * @tr - tracer
- * @tsk - task with the latency
- * @cpu - the cpu of the buffer to copy.
+ * @tr: tracer
+ * @tsk: task with the latency
+ * @cpu: the cpu of the buffer to copy.
  *
  * Flip the trace of a single CPU buffer between the @tr and the max_tr.
  */
@@ -1767,7 +1767,7 @@ static void __init apply_trace_boot_options(void);
 
 /**
  * register_tracer - register a tracer with the ftrace system.
- * @type - the plugin for the tracer
+ * @type: the plugin for the tracer
  *
  * Register a new plugin tracer.
  */
@@ -2230,9 +2230,9 @@ static bool tracing_record_taskinfo_skip(int flags)
 /**
  * tracing_record_taskinfo - record the task info of a task
  *
- * @task  - task to record
- * @flags - TRACE_RECORD_CMDLINE for recording comm
- *        - TRACE_RECORD_TGID for recording tgid
+ * @task task to record
+ * @flags: TRACE_RECORD_CMDLINE for recording comm
+ *         TRACE_RECORD_TGID for recording tgid
  */
 void tracing_record_taskinfo(struct task_struct *task, int flags)
 {
@@ -2258,10 +2258,10 @@ void tracing_record_taskinfo(struct task_struct *task, int flags)
 /**
  * tracing_record_taskinfo_sched_switch - record task info for sched_switch
  *
- * @prev - previous task during sched_switch
- * @next - next task during sched_switch
- * @flags - TRACE_RECORD_CMDLINE for recording comm
- *          TRACE_RECORD_TGID for recording tgid
+ * @prev: previous task during sched_switch
+ * @next: next task during sched_switch
+ * @flags: TRACE_RECORD_CMDLINE for recording comm
+ *         TRACE_RECORD_TGID for recording tgid
  */
 void tracing_record_taskinfo_sched_switch(struct task_struct *prev,
                                          struct task_struct *next, int flags)
@@ -3072,7 +3072,9 @@ static void trace_printk_start_stop_comm(int enabled)
 
 /**
  * trace_vbprintk - write binary msg to tracing buffer
- *
+ * @ip:    The address of the caller
+ * @fmt:   The string format to write to the buffer
+ * @args:  Arguments for @fmt
  */
 int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
 {
index c7506bc..6489308 100644 (file)
@@ -787,7 +787,7 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
        return ret;
 }
 
-static int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
+int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
 {
        char *event = NULL, *sub = NULL, *match;
        int ret;
index dbef0d1..fb6bfbc 100644 (file)
@@ -895,7 +895,8 @@ void trace_probe_cleanup(struct trace_probe *tp)
        for (i = 0; i < tp->nr_args; i++)
                traceprobe_free_probe_arg(&tp->args[i]);
 
-       kfree(call->class->system);
+       if (call->class)
+               kfree(call->class->system);
        kfree(call->name);
        kfree(call->print_fmt);
 }
index f33d66f..4e6b1c3 100644 (file)
@@ -631,6 +631,9 @@ config SBITMAP
 config PARMAN
        tristate "parman" if COMPILE_TEST
 
+config OBJAGG
+       tristate "objagg" if COMPILE_TEST
+
 config STRING_SELFTEST
        tristate "Test string functions"
 
@@ -653,6 +656,3 @@ config GENERIC_LIB_CMPDI2
 
 config GENERIC_LIB_UCMPDI2
        bool
-
-config OBJAGG
-       tristate "objagg" if COMPILE_TEST
index 117ad0e..70dab9a 100644 (file)
@@ -68,7 +68,8 @@ int __kfifo_init(struct __kfifo *fifo, void *buffer,
 {
        size /= esize;
 
-       size = roundup_pow_of_two(size);
+       if (!is_power_of_2(size))
+               size = rounddown_pow_of_two(size);
 
        fifo->in = 0;
        fifo->out = 0;
index feea48f..9050275 100644 (file)
@@ -35,7 +35,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
        struct logic_pio_hwaddr *range;
        resource_size_t start;
        resource_size_t end;
-       resource_size_t mmio_sz = 0;
+       resource_size_t mmio_end = 0;
        resource_size_t iio_sz = MMIO_UPPER_LIMIT;
        int ret = 0;
 
@@ -46,7 +46,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
        end = new_range->hw_start + new_range->size;
 
        mutex_lock(&io_range_mutex);
-       list_for_each_entry_rcu(range, &io_range_list, list) {
+       list_for_each_entry(range, &io_range_list, list) {
                if (range->fwnode == new_range->fwnode) {
                        /* range already there */
                        goto end_register;
@@ -56,7 +56,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
                        /* for MMIO ranges we need to check for overlap */
                        if (start >= range->hw_start + range->size ||
                            end < range->hw_start) {
-                               mmio_sz += range->size;
+                               mmio_end = range->io_start + range->size;
                        } else {
                                ret = -EFAULT;
                                goto end_register;
@@ -69,16 +69,16 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
 
        /* range not registered yet, check for available space */
        if (new_range->flags == LOGIC_PIO_CPU_MMIO) {
-               if (mmio_sz + new_range->size - 1 > MMIO_UPPER_LIMIT) {
+               if (mmio_end + new_range->size - 1 > MMIO_UPPER_LIMIT) {
                        /* if it's too big check if 64K space can be reserved */
-                       if (mmio_sz + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
+                       if (mmio_end + SZ_64K - 1 > MMIO_UPPER_LIMIT) {
                                ret = -E2BIG;
                                goto end_register;
                        }
                        new_range->size = SZ_64K;
                        pr_warn("Requested IO range too big, new size set to 64K\n");
                }
-               new_range->io_start = mmio_sz;
+               new_range->io_start = mmio_end;
        } else if (new_range->flags == LOGIC_PIO_INDIRECT) {
                if (iio_sz + new_range->size - 1 > IO_SPACE_LIMIT) {
                        ret = -E2BIG;
@@ -98,6 +98,20 @@ end_register:
        return ret;
 }
 
+/**
+ * logic_pio_unregister_range - unregister a logical PIO range for a host
+ * @range: pointer to the IO range which has been already registered.
+ *
+ * Unregister a previously-registered IO range node.
+ */
+void logic_pio_unregister_range(struct logic_pio_hwaddr *range)
+{
+       mutex_lock(&io_range_mutex);
+       list_del_rcu(&range->list);
+       mutex_unlock(&io_range_mutex);
+       synchronize_rcu();
+}
+
 /**
  * find_io_range_by_fwnode - find logical PIO range for given FW node
  * @fwnode: FW node handle associated with logical PIO range
@@ -108,26 +122,38 @@ end_register:
  */
 struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
 {
-       struct logic_pio_hwaddr *range;
+       struct logic_pio_hwaddr *range, *found_range = NULL;
 
+       rcu_read_lock();
        list_for_each_entry_rcu(range, &io_range_list, list) {
-               if (range->fwnode == fwnode)
-                       return range;
+               if (range->fwnode == fwnode) {
+                       found_range = range;
+                       break;
+               }
        }
-       return NULL;
+       rcu_read_unlock();
+
+       return found_range;
 }
 
 /* Return a registered range given an input PIO token */
 static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
 {
-       struct logic_pio_hwaddr *range;
+       struct logic_pio_hwaddr *range, *found_range = NULL;
 
+       rcu_read_lock();
        list_for_each_entry_rcu(range, &io_range_list, list) {
-               if (in_range(pio, range->io_start, range->size))
-                       return range;
+               if (in_range(pio, range->io_start, range->size)) {
+                       found_range = range;
+                       break;
+               }
        }
-       pr_err("PIO entry token %lx invalid\n", pio);
-       return NULL;
+       rcu_read_unlock();
+
+       if (!found_range)
+               pr_err("PIO entry token 0x%lx invalid\n", pio);
+
+       return found_range;
 }
 
 /**
@@ -180,14 +206,23 @@ unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
 {
        struct logic_pio_hwaddr *range;
 
+       rcu_read_lock();
        list_for_each_entry_rcu(range, &io_range_list, list) {
                if (range->flags != LOGIC_PIO_CPU_MMIO)
                        continue;
-               if (in_range(addr, range->hw_start, range->size))
-                       return addr - range->hw_start + range->io_start;
+               if (in_range(addr, range->hw_start, range->size)) {
+                       unsigned long cpuaddr;
+
+                       cpuaddr = addr - range->hw_start + range->io_start;
+
+                       rcu_read_unlock();
+                       return cpuaddr;
+               }
        }
-       pr_err("addr %llx not registered in io_range_list\n",
-              (unsigned long long) addr);
+       rcu_read_unlock();
+
+       pr_err("addr %pa not registered in io_range_list\n", &addr);
+
        return ~0UL;
 }
 
index 798275a..26de020 100644 (file)
@@ -124,7 +124,8 @@ EXPORT_SYMBOL_GPL(balloon_page_list_dequeue);
 struct page *balloon_page_alloc(void)
 {
        struct page *page = alloc_page(balloon_mapping_gfp_mask() |
-                                      __GFP_NOMEMALLOC | __GFP_NORETRY);
+                                      __GFP_NOMEMALLOC | __GFP_NORETRY |
+                                      __GFP_NOWARN);
        return page;
 }
 EXPORT_SYMBOL_GPL(balloon_page_alloc);
index 1334ede..de1f159 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/oom.h>
 #include <linux/numa.h>
+#include <linux/page_owner.h>
 
 #include <asm/tlb.h>
 #include <asm/pgalloc.h>
@@ -644,30 +645,40 @@ release:
  *         available
  * never: never stall for any thp allocation
  */
-static inline gfp_t alloc_hugepage_direct_gfpmask(struct vm_area_struct *vma)
+static inline gfp_t alloc_hugepage_direct_gfpmask(struct vm_area_struct *vma, unsigned long addr)
 {
        const bool vma_madvised = !!(vma->vm_flags & VM_HUGEPAGE);
+       gfp_t this_node = 0;
+
+#ifdef CONFIG_NUMA
+       struct mempolicy *pol;
+       /*
+        * __GFP_THISNODE is used only when __GFP_DIRECT_RECLAIM is not
+        * specified, to express a general desire to stay on the current
+        * node for optimistic allocation attempts. If the defrag mode
+        * and/or madvise hint requires the direct reclaim then we prefer
+        * to fallback to other node rather than node reclaim because that
+        * can lead to excessive reclaim even though there is free memory
+        * on other nodes. We expect that NUMA preferences are specified
+        * by memory policies.
+        */
+       pol = get_vma_policy(vma, addr);
+       if (pol->mode != MPOL_BIND)
+               this_node = __GFP_THISNODE;
+       mpol_cond_put(pol);
+#endif
 
-       /* Always do synchronous compaction */
        if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags))
                return GFP_TRANSHUGE | (vma_madvised ? 0 : __GFP_NORETRY);
-
-       /* Kick kcompactd and fail quickly */
        if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags))
-               return GFP_TRANSHUGE_LIGHT | __GFP_KSWAPD_RECLAIM;
-
-       /* Synchronous compaction if madvised, otherwise kick kcompactd */
+               return GFP_TRANSHUGE_LIGHT | __GFP_KSWAPD_RECLAIM | this_node;
        if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags))
-               return GFP_TRANSHUGE_LIGHT |
-                       (vma_madvised ? __GFP_DIRECT_RECLAIM :
-                                       __GFP_KSWAPD_RECLAIM);
-
-       /* Only do synchronous compaction if madvised */
+               return GFP_TRANSHUGE_LIGHT | (vma_madvised ? __GFP_DIRECT_RECLAIM :
+                                                            __GFP_KSWAPD_RECLAIM | this_node);
        if (test_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags))
-               return GFP_TRANSHUGE_LIGHT |
-                      (vma_madvised ? __GFP_DIRECT_RECLAIM : 0);
-
-       return GFP_TRANSHUGE_LIGHT;
+               return GFP_TRANSHUGE_LIGHT | (vma_madvised ? __GFP_DIRECT_RECLAIM :
+                                                            this_node);
+       return GFP_TRANSHUGE_LIGHT | this_node;
 }
 
 /* Caller must hold page table lock. */
@@ -739,8 +750,8 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
                        pte_free(vma->vm_mm, pgtable);
                return ret;
        }
-       gfp = alloc_hugepage_direct_gfpmask(vma);
-       page = alloc_hugepage_vma(gfp, vma, haddr, HPAGE_PMD_ORDER);
+       gfp = alloc_hugepage_direct_gfpmask(vma, haddr);
+       page = alloc_pages_vma(gfp, HPAGE_PMD_ORDER, vma, haddr, numa_node_id());
        if (unlikely(!page)) {
                count_vm_event(THP_FAULT_FALLBACK);
                return VM_FAULT_FALLBACK;
@@ -1347,8 +1358,9 @@ vm_fault_t do_huge_pmd_wp_page(struct vm_fault *vmf, pmd_t orig_pmd)
 alloc:
        if (__transparent_hugepage_enabled(vma) &&
            !transparent_hugepage_debug_cow()) {
-               huge_gfp = alloc_hugepage_direct_gfpmask(vma);
-               new_page = alloc_hugepage_vma(huge_gfp, vma, haddr, HPAGE_PMD_ORDER);
+               huge_gfp = alloc_hugepage_direct_gfpmask(vma, haddr);
+               new_page = alloc_pages_vma(huge_gfp, HPAGE_PMD_ORDER, vma,
+                               haddr, numa_node_id());
        } else
                new_page = NULL;
 
@@ -2505,6 +2517,9 @@ static void __split_huge_page(struct page *page, struct list_head *list,
        }
 
        ClearPageCompound(head);
+
+       split_page_owner(head, HPAGE_PMD_ORDER);
+
        /* See comment in __split_huge_page_tail() */
        if (PageAnon(head)) {
                /* Additional pin to swap cache */
index ede7e7f..6d7296d 100644 (file)
@@ -3856,6 +3856,25 @@ retry:
 
                page = alloc_huge_page(vma, haddr, 0);
                if (IS_ERR(page)) {
+                       /*
+                        * Returning error will result in faulting task being
+                        * sent SIGBUS.  The hugetlb fault mutex prevents two
+                        * tasks from racing to fault in the same page which
+                        * could result in false unable to allocate errors.
+                        * Page migration does not take the fault mutex, but
+                        * does a clear then write of pte's under page table
+                        * lock.  Page fault code could race with migration,
+                        * notice the clear pte and try to allocate a page
+                        * here.  Before returning error, get ptl and make
+                        * sure there really is no pte entry.
+                        */
+                       ptl = huge_pte_lock(h, mm, ptep);
+                       if (!huge_pte_none(huge_ptep_get(ptep))) {
+                               ret = 0;
+                               spin_unlock(ptl);
+                               goto out;
+                       }
+                       spin_unlock(ptl);
                        ret = vmf_error(PTR_ERR(page));
                        goto out;
                }
index 2277b82..95d16a4 100644 (file)
@@ -407,8 +407,14 @@ static inline bool shadow_invalid(u8 tag, s8 shadow_byte)
        if (IS_ENABLED(CONFIG_KASAN_GENERIC))
                return shadow_byte < 0 ||
                        shadow_byte >= KASAN_SHADOW_SCALE_SIZE;
-       else
-               return tag != (u8)shadow_byte;
+
+       /* else CONFIG_KASAN_SW_TAGS: */
+       if ((u8)shadow_byte == KASAN_TAG_INVALID)
+               return true;
+       if ((tag != KASAN_TAG_KERNEL) && (tag != (u8)shadow_byte))
+               return true;
+
+       return false;
 }
 
 static bool __kasan_slab_free(struct kmem_cache *cache, void *object,
index 6e9e8cc..f6e6029 100644 (file)
@@ -1966,6 +1966,7 @@ static void kmemleak_disable(void)
 
        /* stop any memory operation tracing */
        kmemleak_enabled = 0;
+       kmemleak_early_log = 0;
 
        /* check whether it is too early for a kernel thread */
        if (kmemleak_initialized)
@@ -2009,7 +2010,6 @@ void __init kmemleak_init(void)
 
 #ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF
        if (!kmemleak_skip_disable) {
-               kmemleak_early_log = 0;
                kmemleak_disable();
                return;
        }
index cdbb7a8..9ec5e12 100644 (file)
@@ -752,15 +752,13 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
        /* Update memcg */
        __mod_memcg_state(memcg, idx, val);
 
+       /* Update lruvec */
+       __this_cpu_add(pn->lruvec_stat_local->count[idx], val);
+
        x = val + __this_cpu_read(pn->lruvec_stat_cpu->count[idx]);
        if (unlikely(abs(x) > MEMCG_CHARGE_BATCH)) {
                struct mem_cgroup_per_node *pi;
 
-               /*
-                * Batch local counters to keep them in sync with
-                * the hierarchical ones.
-                */
-               __this_cpu_add(pn->lruvec_stat_local->count[idx], x);
                for (pi = pn; pi; pi = parent_nodeinfo(pi, pgdat->node_id))
                        atomic_long_add(x, &pi->lruvec_stat[idx]);
                x = 0;
@@ -768,6 +766,26 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
        __this_cpu_write(pn->lruvec_stat_cpu->count[idx], x);
 }
 
+void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
+{
+       struct page *page = virt_to_head_page(p);
+       pg_data_t *pgdat = page_pgdat(page);
+       struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
+
+       rcu_read_lock();
+       memcg = memcg_from_slab_page(page);
+
+       /* Untracked pages have no memcg, no lruvec. Update only the node */
+       if (!memcg || memcg == root_mem_cgroup) {
+               __mod_node_page_state(pgdat, idx, val);
+       } else {
+               lruvec = mem_cgroup_lruvec(pgdat, memcg);
+               __mod_lruvec_state(lruvec, idx, val);
+       }
+       rcu_read_unlock();
+}
+
 /**
  * __count_memcg_events - account VM events in a cgroup
  * @memcg: the memory cgroup
@@ -1130,26 +1148,45 @@ void mem_cgroup_iter_break(struct mem_cgroup *root,
                css_put(&prev->css);
 }
 
-static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+static void __invalidate_reclaim_iterators(struct mem_cgroup *from,
+                                       struct mem_cgroup *dead_memcg)
 {
-       struct mem_cgroup *memcg = dead_memcg;
        struct mem_cgroup_reclaim_iter *iter;
        struct mem_cgroup_per_node *mz;
        int nid;
        int i;
 
-       for (; memcg; memcg = parent_mem_cgroup(memcg)) {
-               for_each_node(nid) {
-                       mz = mem_cgroup_nodeinfo(memcg, nid);
-                       for (i = 0; i <= DEF_PRIORITY; i++) {
-                               iter = &mz->iter[i];
-                               cmpxchg(&iter->position,
-                                       dead_memcg, NULL);
-                       }
+       for_each_node(nid) {
+               mz = mem_cgroup_nodeinfo(from, nid);
+               for (i = 0; i <= DEF_PRIORITY; i++) {
+                       iter = &mz->iter[i];
+                       cmpxchg(&iter->position,
+                               dead_memcg, NULL);
                }
        }
 }
 
+static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+{
+       struct mem_cgroup *memcg = dead_memcg;
+       struct mem_cgroup *last;
+
+       do {
+               __invalidate_reclaim_iterators(memcg, dead_memcg);
+               last = memcg;
+       } while ((memcg = parent_mem_cgroup(memcg)));
+
+       /*
+        * When cgruop1 non-hierarchy mode is used,
+        * parent_mem_cgroup() does not walk all the way up to the
+        * cgroup root (root_mem_cgroup). So we have to handle
+        * dead_memcg from cgroup root separately.
+        */
+       if (last != root_mem_cgroup)
+               __invalidate_reclaim_iterators(root_mem_cgroup,
+                                               dead_memcg);
+}
+
 /**
  * mem_cgroup_scan_tasks - iterate over tasks of a memory cgroup hierarchy
  * @memcg: hierarchy root
@@ -3221,6 +3258,72 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
        }
 }
 
+static void memcg_flush_percpu_vmstats(struct mem_cgroup *memcg, bool slab_only)
+{
+       unsigned long stat[MEMCG_NR_STAT];
+       struct mem_cgroup *mi;
+       int node, cpu, i;
+       int min_idx, max_idx;
+
+       if (slab_only) {
+               min_idx = NR_SLAB_RECLAIMABLE;
+               max_idx = NR_SLAB_UNRECLAIMABLE;
+       } else {
+               min_idx = 0;
+               max_idx = MEMCG_NR_STAT;
+       }
+
+       for (i = min_idx; i < max_idx; i++)
+               stat[i] = 0;
+
+       for_each_online_cpu(cpu)
+               for (i = min_idx; i < max_idx; i++)
+                       stat[i] += per_cpu(memcg->vmstats_percpu->stat[i], cpu);
+
+       for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+               for (i = min_idx; i < max_idx; i++)
+                       atomic_long_add(stat[i], &mi->vmstats[i]);
+
+       if (!slab_only)
+               max_idx = NR_VM_NODE_STAT_ITEMS;
+
+       for_each_node(node) {
+               struct mem_cgroup_per_node *pn = memcg->nodeinfo[node];
+               struct mem_cgroup_per_node *pi;
+
+               for (i = min_idx; i < max_idx; i++)
+                       stat[i] = 0;
+
+               for_each_online_cpu(cpu)
+                       for (i = min_idx; i < max_idx; i++)
+                               stat[i] += per_cpu(
+                                       pn->lruvec_stat_cpu->count[i], cpu);
+
+               for (pi = pn; pi; pi = parent_nodeinfo(pi, node))
+                       for (i = min_idx; i < max_idx; i++)
+                               atomic_long_add(stat[i], &pi->lruvec_stat[i]);
+       }
+}
+
+static void memcg_flush_percpu_vmevents(struct mem_cgroup *memcg)
+{
+       unsigned long events[NR_VM_EVENT_ITEMS];
+       struct mem_cgroup *mi;
+       int cpu, i;
+
+       for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+               events[i] = 0;
+
+       for_each_online_cpu(cpu)
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       events[i] += per_cpu(memcg->vmstats_percpu->events[i],
+                                            cpu);
+
+       for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       atomic_long_add(events[i], &mi->vmevents[i]);
+}
+
 #ifdef CONFIG_MEMCG_KMEM
 static int memcg_online_kmem(struct mem_cgroup *memcg)
 {
@@ -3270,7 +3373,14 @@ static void memcg_offline_kmem(struct mem_cgroup *memcg)
        if (!parent)
                parent = root_mem_cgroup;
 
+       /*
+        * Deactivate and reparent kmem_caches. Then flush percpu
+        * slab statistics to have precise values at the parent and
+        * all ancestor levels. It's required to keep slab stats
+        * accurate after the reparenting of kmem_caches.
+        */
        memcg_deactivate_kmem_caches(memcg, parent);
+       memcg_flush_percpu_vmstats(memcg, true);
 
        kmemcg_id = memcg->kmemcg_id;
        BUG_ON(kmemcg_id < 0);
@@ -4643,6 +4753,12 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
 {
        int node;
 
+       /*
+        * Flush percpu vmstats and vmevents to guarantee the value correctness
+        * on parent's and all ancestor levels.
+        */
+       memcg_flush_percpu_vmstats(memcg, false);
+       memcg_flush_percpu_vmevents(memcg);
        for_each_node(node)
                free_mem_cgroup_per_node_info(memcg, node);
        free_percpu(memcg->vmstats_percpu);
index f48693f..65e0874 100644 (file)
@@ -403,7 +403,7 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
        },
 };
 
-static void migrate_page_add(struct page *page, struct list_head *pagelist,
+static int migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags);
 
 struct queue_pages {
@@ -429,11 +429,14 @@ static inline bool queue_pages_required(struct page *page,
 }
 
 /*
- * queue_pages_pmd() has three possible return values:
- * 1 - pages are placed on the right node or queued successfully.
- * 0 - THP was split.
- * -EIO - is migration entry or MPOL_MF_STRICT was specified and an existing
- *        page was already on a node that does not follow the policy.
+ * queue_pages_pmd() has four possible return values:
+ * 0 - pages are placed on the right node or queued successfully.
+ * 1 - there is unmovable page, and MPOL_MF_MOVE* & MPOL_MF_STRICT were
+ *     specified.
+ * 2 - THP was split.
+ * -EIO - is migration entry or only MPOL_MF_STRICT was specified and an
+ *        existing page was already on a node that does not follow the
+ *        policy.
  */
 static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
                                unsigned long end, struct mm_walk *walk)
@@ -451,23 +454,20 @@ static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
        if (is_huge_zero_page(page)) {
                spin_unlock(ptl);
                __split_huge_pmd(walk->vma, pmd, addr, false, NULL);
+               ret = 2;
                goto out;
        }
-       if (!queue_pages_required(page, qp)) {
-               ret = 1;
+       if (!queue_pages_required(page, qp))
                goto unlock;
-       }
 
-       ret = 1;
        flags = qp->flags;
        /* go to thp migration */
        if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
-               if (!vma_migratable(walk->vma)) {
-                       ret = -EIO;
+               if (!vma_migratable(walk->vma) ||
+                   migrate_page_add(page, qp->pagelist, flags)) {
+                       ret = 1;
                        goto unlock;
                }
-
-               migrate_page_add(page, qp->pagelist, flags);
        } else
                ret = -EIO;
 unlock:
@@ -479,6 +479,13 @@ out:
 /*
  * Scan through pages checking if pages follow certain conditions,
  * and move them to the pagelist if they do.
+ *
+ * queue_pages_pte_range() has three possible return values:
+ * 0 - pages are placed on the right node or queued successfully.
+ * 1 - there is unmovable page, and MPOL_MF_MOVE* & MPOL_MF_STRICT were
+ *     specified.
+ * -EIO - only MPOL_MF_STRICT was specified and an existing page was already
+ *        on a node that does not follow the policy.
  */
 static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
                        unsigned long end, struct mm_walk *walk)
@@ -488,17 +495,17 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
        struct queue_pages *qp = walk->private;
        unsigned long flags = qp->flags;
        int ret;
+       bool has_unmovable = false;
        pte_t *pte;
        spinlock_t *ptl;
 
        ptl = pmd_trans_huge_lock(pmd, vma);
        if (ptl) {
                ret = queue_pages_pmd(pmd, ptl, addr, end, walk);
-               if (ret > 0)
-                       return 0;
-               else if (ret < 0)
+               if (ret != 2)
                        return ret;
        }
+       /* THP was split, fall through to pte walk */
 
        if (pmd_trans_unstable(pmd))
                return 0;
@@ -519,14 +526,28 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
                if (!queue_pages_required(page, qp))
                        continue;
                if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
-                       if (!vma_migratable(vma))
+                       /* MPOL_MF_STRICT must be specified if we get here */
+                       if (!vma_migratable(vma)) {
+                               has_unmovable = true;
                                break;
-                       migrate_page_add(page, qp->pagelist, flags);
+                       }
+
+                       /*
+                        * Do not abort immediately since there may be
+                        * temporary off LRU pages in the range.  Still
+                        * need migrate other LRU pages.
+                        */
+                       if (migrate_page_add(page, qp->pagelist, flags))
+                               has_unmovable = true;
                } else
                        break;
        }
        pte_unmap_unlock(pte - 1, ptl);
        cond_resched();
+
+       if (has_unmovable)
+               return 1;
+
        return addr != end ? -EIO : 0;
 }
 
@@ -639,7 +660,13 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
  *
  * If pages found in a given range are on a set of nodes (determined by
  * @nodes and @flags,) it's isolated and queued to the pagelist which is
- * passed via @private.)
+ * passed via @private.
+ *
+ * queue_pages_range() has three possible return values:
+ * 1 - there is unmovable page, but MPOL_MF_MOVE* & MPOL_MF_STRICT were
+ *     specified.
+ * 0 - queue pages successfully or no misplaced page.
+ * -EIO - there is misplaced page and only MPOL_MF_STRICT was specified.
  */
 static int
 queue_pages_range(struct mm_struct *mm, unsigned long start, unsigned long end,
@@ -940,7 +967,7 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
 /*
  * page migration, thp tail pages can be passed.
  */
-static void migrate_page_add(struct page *page, struct list_head *pagelist,
+static int migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags)
 {
        struct page *head = compound_head(page);
@@ -953,8 +980,19 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
                        mod_node_page_state(page_pgdat(head),
                                NR_ISOLATED_ANON + page_is_file_cache(head),
                                hpage_nr_pages(head));
+               } else if (flags & MPOL_MF_STRICT) {
+                       /*
+                        * Non-movable page may reach here.  And, there may be
+                        * temporary off LRU pages or non-LRU movable pages.
+                        * Treat them as unmovable pages since they can't be
+                        * isolated, so they can't be moved at the moment.  It
+                        * should return -EIO for this case too.
+                        */
+                       return -EIO;
                }
        }
+
+       return 0;
 }
 
 /* page allocation callback for NUMA node migration */
@@ -1142,8 +1180,8 @@ static struct page *new_page(struct page *page, unsigned long start)
        } else if (PageTransHuge(page)) {
                struct page *thp;
 
-               thp = alloc_hugepage_vma(GFP_TRANSHUGE, vma, address,
-                                        HPAGE_PMD_ORDER);
+               thp = alloc_pages_vma(GFP_TRANSHUGE, HPAGE_PMD_ORDER, vma,
+                               address, numa_node_id());
                if (!thp)
                        return NULL;
                prep_transhuge_page(thp);
@@ -1157,9 +1195,10 @@ static struct page *new_page(struct page *page, unsigned long start)
 }
 #else
 
-static void migrate_page_add(struct page *page, struct list_head *pagelist,
+static int migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags)
 {
+       return -EIO;
 }
 
 int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from,
@@ -1182,6 +1221,7 @@ static long do_mbind(unsigned long start, unsigned long len,
        struct mempolicy *new;
        unsigned long end;
        int err;
+       int ret;
        LIST_HEAD(pagelist);
 
        if (flags & ~(unsigned long)MPOL_MF_VALID)
@@ -1243,10 +1283,15 @@ static long do_mbind(unsigned long start, unsigned long len,
        if (err)
                goto mpol_out;
 
-       err = queue_pages_range(mm, start, end, nmask,
+       ret = queue_pages_range(mm, start, end, nmask,
                          flags | MPOL_MF_INVERT, &pagelist);
-       if (!err)
-               err = mbind_range(mm, start, end, new);
+
+       if (ret < 0) {
+               err = -EIO;
+               goto up_out;
+       }
+
+       err = mbind_range(mm, start, end, new);
 
        if (!err) {
                int nr_failed = 0;
@@ -1259,13 +1304,14 @@ static long do_mbind(unsigned long start, unsigned long len,
                                putback_movable_pages(&pagelist);
                }
 
-               if (nr_failed && (flags & MPOL_MF_STRICT))
+               if ((ret > 0) || (nr_failed && (flags & MPOL_MF_STRICT)))
                        err = -EIO;
        } else
                putback_movable_pages(&pagelist);
 
+up_out:
        up_write(&mm->mmap_sem);
- mpol_out:
+mpol_out:
        mpol_put(new);
        return err;
 }
@@ -1688,7 +1734,7 @@ struct mempolicy *__get_vma_policy(struct vm_area_struct *vma,
  * freeing by another task.  It is the caller's responsibility to free the
  * extra reference for shared policies.
  */
-static struct mempolicy *get_vma_policy(struct vm_area_struct *vma,
+struct mempolicy *get_vma_policy(struct vm_area_struct *vma,
                                                unsigned long addr)
 {
        struct mempolicy *pol = __get_vma_policy(vma, addr);
@@ -2037,7 +2083,6 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
  *     @vma:  Pointer to VMA or NULL if not available.
  *     @addr: Virtual Address of the allocation. Must be inside the VMA.
  *     @node: Which node to prefer for allocation (modulo policy).
- *     @hugepage: for hugepages try only the preferred node if possible
  *
  *     This function allocates a page from the kernel page pool and applies
  *     a NUMA policy associated with the VMA or the current process.
@@ -2048,7 +2093,7 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
  */
 struct page *
 alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
-               unsigned long addr, int node, bool hugepage)
+               unsigned long addr, int node)
 {
        struct mempolicy *pol;
        struct page *page;
@@ -2066,31 +2111,6 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
                goto out;
        }
 
-       if (unlikely(IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && hugepage)) {
-               int hpage_node = node;
-
-               /*
-                * For hugepage allocation and non-interleave policy which
-                * allows the current node (or other explicitly preferred
-                * node) we only try to allocate from the current/preferred
-                * node and don't fall back to other nodes, as the cost of
-                * remote accesses would likely offset THP benefits.
-                *
-                * If the policy is interleave, or does not allow the current
-                * node in its nodemask, we allocate the standard way.
-                */
-               if (pol->mode == MPOL_PREFERRED && !(pol->flags & MPOL_F_LOCAL))
-                       hpage_node = pol->v.preferred_node;
-
-               nmask = policy_nodemask(gfp, pol);
-               if (!nmask || node_isset(hpage_node, *nmask)) {
-                       mpol_cond_put(pol);
-                       page = __alloc_pages_node(hpage_node,
-                                               gfp | __GFP_THISNODE, order);
-                       goto out;
-               }
-       }
-
        nmask = policy_nodemask(gfp, pol);
        preferred_nid = policy_node(gfp, pol, node);
        page = __alloc_pages_nodemask(gfp, order, preferred_nid, nmask);
index 8643265..ed70c4e 100644 (file)
@@ -403,6 +403,30 @@ void __put_devmap_managed_page(struct page *page)
 
                mem_cgroup_uncharge(page);
 
+               /*
+                * When a device_private page is freed, the page->mapping field
+                * may still contain a (stale) mapping value. For example, the
+                * lower bits of page->mapping may still identify the page as
+                * an anonymous page. Ultimately, this entire field is just
+                * stale and wrong, and it will cause errors if not cleared.
+                * One example is:
+                *
+                *  migrate_vma_pages()
+                *    migrate_vma_insert_page()
+                *      page_add_new_anon_rmap()
+                *        __page_set_anon_rmap()
+                *          ...checks page->mapping, via PageAnon(page) call,
+                *            and incorrectly concludes that the page is an
+                *            anonymous page. Therefore, it incorrectly,
+                *            silently fails to set up the new anon rmap.
+                *
+                * For other types of ZONE_DEVICE pages, migration is either
+                * handled differently or not done at all, so there is no need
+                * to clear page->mapping.
+                */
+               if (is_device_private_page(page))
+                       page->mapping = NULL;
+
                page->pgmap->ops->page_free(page);
        } else if (!count)
                __put_page(page);
index 272c6de..9c91949 100644 (file)
@@ -2238,27 +2238,12 @@ static int move_freepages(struct zone *zone,
        unsigned int order;
        int pages_moved = 0;
 
-#ifndef CONFIG_HOLES_IN_ZONE
-       /*
-        * page_zone is not safe to call in this context when
-        * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant
-        * anyway as we check zone boundaries in move_freepages_block().
-        * Remove at a later date when no bug reports exist related to
-        * grouping pages by mobility
-        */
-       VM_BUG_ON(pfn_valid(page_to_pfn(start_page)) &&
-                 pfn_valid(page_to_pfn(end_page)) &&
-                 page_zone(start_page) != page_zone(end_page));
-#endif
        for (page = start_page; page <= end_page;) {
                if (!pfn_valid_within(page_to_pfn(page))) {
                        page++;
                        continue;
                }
 
-               /* Make sure we are not inadvertently changing nodes */
-               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
                if (!PageBuddy(page)) {
                        /*
                         * We assume that pages that could be isolated for
@@ -2273,6 +2258,10 @@ static int move_freepages(struct zone *zone,
                        continue;
                }
 
+               /* Make sure we are not inadvertently changing nodes */
+               VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+               VM_BUG_ON_PAGE(page_zone(page) != zone, page);
+
                order = page_order(page);
                move_to_free_area(page, &zone->free_area[order], migratetype);
                page += 1 << order;
index e5dfe2a..003377e 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1475,7 +1475,15 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                        /*
                         * No need to invalidate here it will synchronize on
                         * against the special swap migration pte.
+                        *
+                        * The assignment to subpage above was computed from a
+                        * swap PTE which results in an invalid pointer.
+                        * Since only PAGE_SIZE pages can currently be
+                        * migrated, just set it to page. This will need to be
+                        * changed when hugepage migrations to device private
+                        * memory are supported.
                         */
+                       subpage = page;
                        goto discard;
                }
 
index 626d8c7..2bed476 100644 (file)
@@ -1466,7 +1466,7 @@ static struct page *shmem_alloc_hugepage(gfp_t gfp,
 
        shmem_pseudo_vma_init(&pvma, info, hindex);
        page = alloc_pages_vma(gfp | __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN,
-                       HPAGE_PMD_ORDER, &pvma, 0, numa_node_id(), true);
+                       HPAGE_PMD_ORDER, &pvma, 0, numa_node_id());
        shmem_pseudo_vma_destroy(&pvma);
        if (page)
                prep_transhuge_page(page);
index 2a09796..98e9248 100644 (file)
@@ -147,7 +147,7 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
                                       bool to_user)
 {
        /* Reject if object wraps past end of memory. */
-       if (ptr + n < ptr)
+       if (ptr + (n - 1) < ptr)
                usercopy_abort("wrapped address", NULL, to_user, 0, ptr + n);
 
        /* Reject if NULL or ZERO-allocation. */
index e0fc963..7ba11e1 100644 (file)
@@ -3278,10 +3278,20 @@ retry:
                if (va == NULL)
                        goto overflow;
 
+               /*
+                * If required width exeeds current VA block, move
+                * base downwards and then recheck.
+                */
+               if (base + end > va->va_end) {
+                       base = pvm_determine_end_from_reverse(&va, align) - end;
+                       term_area = area;
+                       continue;
+               }
+
                /*
                 * If this VA does not fit, move base downwards and recheck.
                 */
-               if (base + start < va->va_start || base + end > va->va_end) {
+               if (base + start < va->va_start) {
                        va = node_to_va(rb_prev(&va->rb_node));
                        base = pvm_determine_end_from_reverse(&va, align) - end;
                        term_area = area;
index dbdc46a..a6c5d0b 100644 (file)
@@ -88,9 +88,6 @@ struct scan_control {
        /* Can pages be swapped as part of reclaim? */
        unsigned int may_swap:1;
 
-       /* e.g. boosted watermark reclaim leaves slabs alone */
-       unsigned int may_shrinkslab:1;
-
        /*
         * Cgroups are not reclaimed below their configured memory.low,
         * unless we threaten to OOM. If any cgroups are skipped due to
@@ -2714,10 +2711,8 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc)
                        shrink_node_memcg(pgdat, memcg, sc, &lru_pages);
                        node_lru_pages += lru_pages;
 
-                       if (sc->may_shrinkslab) {
-                               shrink_slab(sc->gfp_mask, pgdat->node_id,
-                                   memcg, sc->priority);
-                       }
+                       shrink_slab(sc->gfp_mask, pgdat->node_id, memcg,
+                                       sc->priority);
 
                        /* Record the group's reclaim efficiency */
                        vmpressure(sc->gfp_mask, memcg, false,
@@ -3194,7 +3189,6 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
                .may_swap = 1,
-               .may_shrinkslab = 1,
        };
 
        /*
@@ -3226,6 +3220,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
 #ifdef CONFIG_MEMCG
 
+/* Only used by soft limit reclaim. Do not reuse for anything else. */
 unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                                                gfp_t gfp_mask, bool noswap,
                                                pg_data_t *pgdat,
@@ -3238,11 +3233,11 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
                .may_unmap = 1,
                .reclaim_idx = MAX_NR_ZONES - 1,
                .may_swap = !noswap,
-               .may_shrinkslab = 1,
        };
        unsigned long lru_pages;
 
-       set_task_reclaim_state(current, &sc.reclaim_state);
+       WARN_ON_ONCE(!current->reclaim_state);
+
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                        (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
 
@@ -3260,7 +3255,6 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
-       set_task_reclaim_state(current, NULL);
        *nr_scanned = sc.nr_scanned;
 
        return sc.nr_reclaimed;
@@ -3286,7 +3280,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .may_writepage = !laptop_mode,
                .may_unmap = 1,
                .may_swap = may_swap,
-               .may_shrinkslab = 1,
        };
 
        set_task_reclaim_state(current, &sc.reclaim_state);
@@ -3598,7 +3591,6 @@ restart:
                 */
                sc.may_writepage = !laptop_mode && !nr_boost_reclaim;
                sc.may_swap = !nr_boost_reclaim;
-               sc.may_shrinkslab = !nr_boost_reclaim;
 
                /*
                 * Do some background aging of the anon list, to give
index e0b4edc..c963831 100644 (file)
@@ -380,14 +380,12 @@ void workingset_update_node(struct xa_node *node)
        if (node->count && node->count == node->nr_values) {
                if (list_empty(&node->private_list)) {
                        list_lru_add(&shadow_nodes, &node->private_list);
-                       __inc_lruvec_page_state(virt_to_page(node),
-                                               WORKINGSET_NODES);
+                       __inc_lruvec_slab_state(node, WORKINGSET_NODES);
                }
        } else {
                if (!list_empty(&node->private_list)) {
                        list_lru_del(&shadow_nodes, &node->private_list);
-                       __dec_lruvec_page_state(virt_to_page(node),
-                                               WORKINGSET_NODES);
+                       __dec_lruvec_slab_state(node, WORKINGSET_NODES);
                }
        }
 }
@@ -480,7 +478,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
        }
 
        list_lru_isolate(lru, item);
-       __dec_lruvec_page_state(virt_to_page(node), WORKINGSET_NODES);
+       __dec_lruvec_slab_state(node, WORKINGSET_NODES);
 
        spin_unlock(lru_lock);
 
@@ -503,7 +501,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
         * shadow entries we were tracking ...
         */
        xas_store(&xas, NULL);
-       __inc_lruvec_page_state(virt_to_page(node), WORKINGSET_NODERECLAIM);
+       __inc_lruvec_slab_state(node, WORKINGSET_NODERECLAIM);
 
 out_invalid:
        xa_unlock_irq(&mapping->i_pages);
index 1a029a7..75b7962 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <linux/zpool.h>
 #include <linux/magic.h>
 
@@ -145,6 +146,8 @@ struct z3fold_header {
  * @release_wq:        workqueue for safe page release
  * @work:      work_struct for safe page release
  * @inode:     inode for z3fold pseudo filesystem
+ * @destroying: bool to stop migration once we start destruction
+ * @isolated: int to count the number of pages currently in isolation
  *
  * This structure is allocated at pool creation time and maintains metadata
  * pertaining to a particular z3fold pool.
@@ -163,8 +166,11 @@ struct z3fold_pool {
        const struct zpool_ops *zpool_ops;
        struct workqueue_struct *compact_wq;
        struct workqueue_struct *release_wq;
+       struct wait_queue_head isolate_wait;
        struct work_struct work;
        struct inode *inode;
+       bool destroying;
+       int isolated;
 };
 
 /*
@@ -769,6 +775,7 @@ static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
                goto out_c;
        spin_lock_init(&pool->lock);
        spin_lock_init(&pool->stale_lock);
+       init_waitqueue_head(&pool->isolate_wait);
        pool->unbuddied = __alloc_percpu(sizeof(struct list_head)*NCHUNKS, 2);
        if (!pool->unbuddied)
                goto out_pool;
@@ -808,6 +815,15 @@ out:
        return NULL;
 }
 
+static bool pool_isolated_are_drained(struct z3fold_pool *pool)
+{
+       bool ret;
+
+       spin_lock(&pool->lock);
+       ret = pool->isolated == 0;
+       spin_unlock(&pool->lock);
+       return ret;
+}
 /**
  * z3fold_destroy_pool() - destroys an existing z3fold pool
  * @pool:      the z3fold pool to be destroyed
@@ -817,9 +833,35 @@ out:
 static void z3fold_destroy_pool(struct z3fold_pool *pool)
 {
        kmem_cache_destroy(pool->c_handle);
-       z3fold_unregister_migration(pool);
-       destroy_workqueue(pool->release_wq);
+       /*
+        * We set pool-> destroying under lock to ensure that
+        * z3fold_page_isolate() sees any changes to destroying. This way we
+        * avoid the need for any memory barriers.
+        */
+
+       spin_lock(&pool->lock);
+       pool->destroying = true;
+       spin_unlock(&pool->lock);
+
+       /*
+        * We need to ensure that no pages are being migrated while we destroy
+        * these workqueues, as migration can queue work on either of the
+        * workqueues.
+        */
+       wait_event(pool->isolate_wait, !pool_isolated_are_drained(pool));
+
+       /*
+        * We need to destroy pool->compact_wq before pool->release_wq,
+        * as any pending work on pool->compact_wq will call
+        * queue_work(pool->release_wq, &pool->work).
+        *
+        * There are still outstanding pages until both workqueues are drained,
+        * so we cannot unregister migration until then.
+        */
+
        destroy_workqueue(pool->compact_wq);
+       destroy_workqueue(pool->release_wq);
+       z3fold_unregister_migration(pool);
        kfree(pool);
 }
 
@@ -1297,6 +1339,28 @@ static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
        return atomic64_read(&pool->pages_nr);
 }
 
+/*
+ * z3fold_dec_isolated() expects to be called while pool->lock is held.
+ */
+static void z3fold_dec_isolated(struct z3fold_pool *pool)
+{
+       assert_spin_locked(&pool->lock);
+       VM_BUG_ON(pool->isolated <= 0);
+       pool->isolated--;
+
+       /*
+        * If we have no more isolated pages, we have to see if
+        * z3fold_destroy_pool() is waiting for a signal.
+        */
+       if (pool->isolated == 0 && waitqueue_active(&pool->isolate_wait))
+               wake_up_all(&pool->isolate_wait);
+}
+
+static void z3fold_inc_isolated(struct z3fold_pool *pool)
+{
+       pool->isolated++;
+}
+
 static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
 {
        struct z3fold_header *zhdr;
@@ -1323,6 +1387,34 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
                spin_lock(&pool->lock);
                if (!list_empty(&page->lru))
                        list_del(&page->lru);
+               /*
+                * We need to check for destruction while holding pool->lock, as
+                * otherwise destruction could see 0 isolated pages, and
+                * proceed.
+                */
+               if (unlikely(pool->destroying)) {
+                       spin_unlock(&pool->lock);
+                       /*
+                        * If this page isn't stale, somebody else holds a
+                        * reference to it. Let't drop our refcount so that they
+                        * can call the release logic.
+                        */
+                       if (unlikely(kref_put(&zhdr->refcount,
+                                             release_z3fold_page_locked))) {
+                               /*
+                                * If we get here we have kref problems, so we
+                                * should freak out.
+                                */
+                               WARN(1, "Z3fold is experiencing kref problems\n");
+                               z3fold_page_unlock(zhdr);
+                               return false;
+                       }
+                       z3fold_page_unlock(zhdr);
+                       return false;
+               }
+
+
+               z3fold_inc_isolated(pool);
                spin_unlock(&pool->lock);
                z3fold_page_unlock(zhdr);
                return true;
@@ -1391,6 +1483,10 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
 
        queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
 
+       spin_lock(&pool->lock);
+       z3fold_dec_isolated(pool);
+       spin_unlock(&pool->lock);
+
        page_mapcount_reset(page);
        put_page(page);
        return 0;
@@ -1410,10 +1506,14 @@ static void z3fold_page_putback(struct page *page)
        INIT_LIST_HEAD(&page->lru);
        if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
                atomic64_dec(&pool->pages_nr);
+               spin_lock(&pool->lock);
+               z3fold_dec_isolated(pool);
+               spin_unlock(&pool->lock);
                return;
        }
        spin_lock(&pool->lock);
        list_add(&page->lru, &pool->lru);
+       z3fold_dec_isolated(pool);
        spin_unlock(&pool->lock);
        z3fold_page_unlock(zhdr);
 }
index 57fbb7c..e98bb6a 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/mount.h>
 #include <linux/pseudo_fs.h>
 #include <linux/migrate.h>
+#include <linux/wait.h>
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 
@@ -268,6 +269,10 @@ struct zs_pool {
 #ifdef CONFIG_COMPACTION
        struct inode *inode;
        struct work_struct free_work;
+       /* A wait queue for when migration races with async_free_zspage() */
+       struct wait_queue_head migration_wait;
+       atomic_long_t isolated_pages;
+       bool destroying;
 #endif
 };
 
@@ -1862,6 +1867,31 @@ static void dec_zspage_isolation(struct zspage *zspage)
        zspage->isolated--;
 }
 
+static void putback_zspage_deferred(struct zs_pool *pool,
+                                   struct size_class *class,
+                                   struct zspage *zspage)
+{
+       enum fullness_group fg;
+
+       fg = putback_zspage(class, zspage);
+       if (fg == ZS_EMPTY)
+               schedule_work(&pool->free_work);
+
+}
+
+static inline void zs_pool_dec_isolated(struct zs_pool *pool)
+{
+       VM_BUG_ON(atomic_long_read(&pool->isolated_pages) <= 0);
+       atomic_long_dec(&pool->isolated_pages);
+       /*
+        * There's no possibility of racing, since wait_for_isolated_drain()
+        * checks the isolated count under &class->lock after enqueuing
+        * on migration_wait.
+        */
+       if (atomic_long_read(&pool->isolated_pages) == 0 && pool->destroying)
+               wake_up_all(&pool->migration_wait);
+}
+
 static void replace_sub_page(struct size_class *class, struct zspage *zspage,
                                struct page *newpage, struct page *oldpage)
 {
@@ -1931,6 +1961,7 @@ static bool zs_page_isolate(struct page *page, isolate_mode_t mode)
         */
        if (!list_empty(&zspage->list) && !is_zspage_isolated(zspage)) {
                get_zspage_mapping(zspage, &class_idx, &fullness);
+               atomic_long_inc(&pool->isolated_pages);
                remove_zspage(class, zspage, fullness);
        }
 
@@ -2030,8 +2061,16 @@ static int zs_page_migrate(struct address_space *mapping, struct page *newpage,
         * Page migration is done so let's putback isolated zspage to
         * the list if @page is final isolated subpage in the zspage.
         */
-       if (!is_zspage_isolated(zspage))
-               putback_zspage(class, zspage);
+       if (!is_zspage_isolated(zspage)) {
+               /*
+                * We cannot race with zs_destroy_pool() here because we wait
+                * for isolation to hit zero before we start destroying.
+                * Also, we ensure that everyone can see pool->destroying before
+                * we start waiting.
+                */
+               putback_zspage_deferred(pool, class, zspage);
+               zs_pool_dec_isolated(pool);
+       }
 
        reset_page(page);
        put_page(page);
@@ -2077,13 +2116,12 @@ static void zs_page_putback(struct page *page)
        spin_lock(&class->lock);
        dec_zspage_isolation(zspage);
        if (!is_zspage_isolated(zspage)) {
-               fg = putback_zspage(class, zspage);
                /*
                 * Due to page_lock, we cannot free zspage immediately
                 * so let's defer.
                 */
-               if (fg == ZS_EMPTY)
-                       schedule_work(&pool->free_work);
+               putback_zspage_deferred(pool, class, zspage);
+               zs_pool_dec_isolated(pool);
        }
        spin_unlock(&class->lock);
 }
@@ -2107,8 +2145,36 @@ static int zs_register_migration(struct zs_pool *pool)
        return 0;
 }
 
+static bool pool_isolated_are_drained(struct zs_pool *pool)
+{
+       return atomic_long_read(&pool->isolated_pages) == 0;
+}
+
+/* Function for resolving migration */
+static void wait_for_isolated_drain(struct zs_pool *pool)
+{
+
+       /*
+        * We're in the process of destroying the pool, so there are no
+        * active allocations. zs_page_isolate() fails for completely free
+        * zspages, so we need only wait for the zs_pool's isolated
+        * count to hit zero.
+        */
+       wait_event(pool->migration_wait,
+                  pool_isolated_are_drained(pool));
+}
+
 static void zs_unregister_migration(struct zs_pool *pool)
 {
+       pool->destroying = true;
+       /*
+        * We need a memory barrier here to ensure global visibility of
+        * pool->destroying. Thus pool->isolated pages will either be 0 in which
+        * case we don't care, or it will be > 0 and pool->destroying will
+        * ensure that we wake up once isolation hits 0.
+        */
+       smp_mb();
+       wait_for_isolated_drain(pool); /* This can block */
        flush_work(&pool->free_work);
        iput(pool->inode);
 }
@@ -2346,6 +2412,10 @@ struct zs_pool *zs_create_pool(const char *name)
        if (!pool->name)
                goto err;
 
+#ifdef CONFIG_COMPACTION
+       init_waitqueue_head(&pool->migration_wait);
+#endif
+
        if (create_cache(pool))
                goto err;
 
index 240ed70..d78938e 100644 (file)
@@ -277,17 +277,23 @@ static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv)
  * batadv_iv_ogm_aggr_packet() - checks if there is another OGM attached
  * @buff_pos: current position in the skb
  * @packet_len: total length of the skb
- * @tvlv_len: tvlv length of the previously considered OGM
+ * @ogm_packet: potential OGM in buffer
  *
  * Return: true if there is enough space for another OGM, false otherwise.
  */
-static bool batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
-                                     __be16 tvlv_len)
+static bool
+batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
+                         const struct batadv_ogm_packet *ogm_packet)
 {
        int next_buff_pos = 0;
 
-       next_buff_pos += buff_pos + BATADV_OGM_HLEN;
-       next_buff_pos += ntohs(tvlv_len);
+       /* check if there is enough space for the header */
+       next_buff_pos += buff_pos + sizeof(*ogm_packet);
+       if (next_buff_pos > packet_len)
+               return false;
+
+       /* check if there is enough space for the optional TVLV */
+       next_buff_pos += ntohs(ogm_packet->tvlv_len);
 
        return (next_buff_pos <= packet_len) &&
               (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
@@ -315,7 +321,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
 
        /* adjust all flags and log packets */
        while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
-                                        batadv_ogm_packet->tvlv_len)) {
+                                        batadv_ogm_packet)) {
                /* we might have aggregated direct link packets with an
                 * ordinary base packet
                 */
@@ -1704,7 +1710,7 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
 
        /* unpack the aggregated packets and process them one by one */
        while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
-                                        ogm_packet->tvlv_len)) {
+                                        ogm_packet)) {
                batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
 
                ogm_offset += BATADV_OGM_HLEN;
index fad95ef..bc06e3c 100644 (file)
@@ -631,17 +631,23 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
  * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated
  * @buff_pos: current position in the skb
  * @packet_len: total length of the skb
- * @tvlv_len: tvlv length of the previously considered OGM
+ * @ogm2_packet: potential OGM2 in buffer
  *
  * Return: true if there is enough space for another OGM, false otherwise.
  */
-static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
-                                    __be16 tvlv_len)
+static bool
+batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
+                        const struct batadv_ogm2_packet *ogm2_packet)
 {
        int next_buff_pos = 0;
 
-       next_buff_pos += buff_pos + BATADV_OGM2_HLEN;
-       next_buff_pos += ntohs(tvlv_len);
+       /* check if there is enough space for the header */
+       next_buff_pos += buff_pos + sizeof(*ogm2_packet);
+       if (next_buff_pos > packet_len)
+               return false;
+
+       /* check if there is enough space for the optional TVLV */
+       next_buff_pos += ntohs(ogm2_packet->tvlv_len);
 
        return (next_buff_pos <= packet_len) &&
               (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
@@ -818,7 +824,7 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
        ogm_packet = (struct batadv_ogm2_packet *)skb->data;
 
        while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
-                                       ogm_packet->tvlv_len)) {
+                                       ogm_packet)) {
                batadv_v_ogm_process(skb, ogm_offset, if_incoming);
 
                ogm_offset += BATADV_OGM2_HLEN;
index 67d7f83..1d5bdf3 100644 (file)
@@ -2303,7 +2303,7 @@ __batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid,
 
        while (bucket_tmp < hash->size) {
                if (batadv_mcast_flags_dump_bucket(msg, portid, cb, hash,
-                                                  *bucket, &idx_tmp))
+                                                  bucket_tmp, &idx_tmp))
                        break;
 
                bucket_tmp++;
@@ -2420,8 +2420,10 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
        batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
        batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
        batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
-       batadv_mcast_want_rtr4_update(bat_priv, orig, BATADV_NO_FLAGS);
-       batadv_mcast_want_rtr6_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_rtr4_update(bat_priv, orig,
+                                     BATADV_MCAST_WANT_NO_RTR4);
+       batadv_mcast_want_rtr6_update(bat_priv, orig,
+                                     BATADV_MCAST_WANT_NO_RTR6);
 
        spin_unlock_bh(&orig->mcast_handler_lock);
 }
index 6f08fd1..7e052d6 100644 (file)
@@ -164,7 +164,7 @@ batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype)
 {
        struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
 
-       return attr ? nla_get_u32(attr) : 0;
+       return (attr && nla_len(attr) == sizeof(u32)) ? nla_get_u32(attr) : 0;
 }
 
 /**
index b9585e7..04bc793 100644 (file)
@@ -3202,6 +3202,7 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->conn_info_min_age = DEFAULT_CONN_INFO_MIN_AGE;
        hdev->conn_info_max_age = DEFAULT_CONN_INFO_MAX_AGE;
        hdev->auth_payload_timeout = DEFAULT_AUTH_PAYLOAD_TIMEOUT;
+       hdev->min_enc_key_size = HCI_MIN_ENC_KEY_SIZE;
 
        mutex_init(&hdev->lock);
        mutex_init(&hdev->req_lock);
index bb67f4a..402e2cc 100644 (file)
@@ -433,6 +433,35 @@ static int auto_accept_delay_set(void *data, u64 val)
        return 0;
 }
 
+static int min_encrypt_key_size_set(void *data, u64 val)
+{
+       struct hci_dev *hdev = data;
+
+       if (val < 1 || val > 16)
+               return -EINVAL;
+
+       hci_dev_lock(hdev);
+       hdev->min_enc_key_size = val;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int min_encrypt_key_size_get(void *data, u64 *val)
+{
+       struct hci_dev *hdev = data;
+
+       hci_dev_lock(hdev);
+       *val = hdev->min_enc_key_size;
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(min_encrypt_key_size_fops,
+                       min_encrypt_key_size_get,
+                       min_encrypt_key_size_set, "%llu\n");
+
 static int auto_accept_delay_get(void *data, u64 *val)
 {
        struct hci_dev *hdev = data;
@@ -545,6 +574,8 @@ void hci_debugfs_create_bredr(struct hci_dev *hdev)
        if (lmp_ssp_capable(hdev)) {
                debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs,
                                    hdev, &ssp_debug_mode_fops);
+               debugfs_create_file("min_encrypt_key_size", 0644, hdev->debugfs,
+                                   hdev, &min_encrypt_key_size_fops);
                debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs,
                                    hdev, &auto_accept_delay_fops);
        }
index cdb00c2..c1d3a30 100644 (file)
@@ -5660,11 +5660,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_UNKNOWN_CONN_ID);
 
-       if (min < hcon->le_conn_min_interval ||
-           max > hcon->le_conn_max_interval)
-               return send_conn_param_neg_reply(hdev, handle,
-                                                HCI_ERROR_INVALID_LL_PARAMS);
-
        if (hci_check_conn_params(min, max, latency, timeout))
                return send_conn_param_neg_reply(hdev, handle,
                                                 HCI_ERROR_INVALID_LL_PARAMS);
index 5abd423..8d88996 100644 (file)
@@ -101,6 +101,7 @@ static int hidp_send_message(struct hidp_session *session, struct socket *sock,
 {
        struct sk_buff *skb;
        struct sock *sk = sock->sk;
+       int ret;
 
        BT_DBG("session %p data %p size %d", session, data, size);
 
@@ -114,13 +115,17 @@ static int hidp_send_message(struct hidp_session *session, struct socket *sock,
        }
 
        skb_put_u8(skb, hdr);
-       if (data && size > 0)
+       if (data && size > 0) {
                skb_put_data(skb, data, size);
+               ret = size;
+       } else {
+               ret = 0;
+       }
 
        skb_queue_tail(transmit, skb);
        wake_up_interruptible(sk_sleep(sk));
 
-       return 0;
+       return ret;
 }
 
 static int hidp_send_ctrl_message(struct hidp_session *session,
index cc506fe..da7fdbd 100644 (file)
@@ -1361,7 +1361,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
         * actually encrypted before enforcing a key size.
         */
        return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
-               hcon->enc_key_size >= HCI_MIN_ENC_KEY_SIZE);
+               hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
@@ -5305,14 +5305,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
        memset(&rsp, 0, sizeof(rsp));
 
-       if (min < hcon->le_conn_min_interval ||
-           max > hcon->le_conn_max_interval) {
-               BT_DBG("requested connection interval exceeds current bounds.");
-               err = -EINVAL;
-       } else {
-               err = hci_check_conn_params(min, max, latency, to_multiplier);
-       }
-
+       err = hci_check_conn_params(min, max, latency, to_multiplier);
        if (err)
                rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
        else
index bf6acd3..63f9c08 100644 (file)
@@ -437,7 +437,7 @@ static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
        struct nlmsghdr *nlh;
        struct nlattr *nest;
 
-       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), 0);
        if (!nlh)
                return -EMSGSIZE;
 
index d3f9592..af78001 100644 (file)
@@ -496,6 +496,10 @@ static unsigned int br_nf_pre_routing(void *priv,
                if (!brnet->call_ip6tables &&
                    !br_opt_get(br, BROPT_NF_CALL_IP6TABLES))
                        return NF_ACCEPT;
+               if (!ipv6_mod_enabled()) {
+                       pr_warn_once("Module ipv6 is disabled, so call_ip6tables is not supported.");
+                       return NF_DROP;
+               }
 
                nf_bridge_pull_encap_header_rcsum(skb);
                return br_nf_pre_routing_ipv6(priv, skb, state);
index c8177a8..4096d8a 100644 (file)
@@ -221,7 +221,7 @@ unsigned int ebt_do_table(struct sk_buff *skb,
                        return NF_DROP;
                }
 
-               ADD_COUNTER(*(counter_base + i), 1, skb->len);
+               ADD_COUNTER(*(counter_base + i), skb->len, 1);
 
                /* these should only watch: not modify, nor tell us
                 * what to do with the packet
@@ -959,8 +959,8 @@ static void get_counters(const struct ebt_counter *oldcounters,
                        continue;
                counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
                for (i = 0; i < nentries; i++)
-                       ADD_COUNTER(counters[i], counter_base[i].pcnt,
-                                   counter_base[i].bcnt);
+                       ADD_COUNTER(counters[i], counter_base[i].bcnt,
+                                   counter_base[i].pcnt);
        }
 }
 
@@ -1280,7 +1280,7 @@ static int do_update_counters(struct net *net, const char *name,
 
        /* we add to the counters of the first cpu */
        for (i = 0; i < num_counters; i++)
-               ADD_COUNTER(t->private->counters[i], tmp[i].pcnt, tmp[i].bcnt);
+               ADD_COUNTER(t->private->counters[i], tmp[i].bcnt, tmp[i].pcnt);
 
        write_unlock_bh(&t->lock);
        ret = 0;
index 1804e86..7c9e92b 100644 (file)
@@ -53,7 +53,7 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
                        goto err;
 
                br_vlan_get_proto(br_dev, &p_proto);
-               nft_reg_store16(dest, p_proto);
+               nft_reg_store16(dest, htons(p_proto));
                return;
        }
        default:
index 5d6724c..4f75df4 100644 (file)
@@ -136,8 +136,10 @@ void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
        if (key) {
                kfree(key->key);
                key->key = NULL;
-               crypto_free_sync_skcipher(key->tfm);
-               key->tfm = NULL;
+               if (key->tfm) {
+                       crypto_free_sync_skcipher(key->tfm);
+                       key->tfm = NULL;
+               }
        }
 }
 
index 0b2df09..78ae6e8 100644 (file)
@@ -1496,7 +1496,7 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
        struct ceph_osds up, acting;
        bool force_resend = false;
        bool unpaused = false;
-       bool legacy_change;
+       bool legacy_change = false;
        bool split = false;
        bool sort_bitwise = ceph_osdmap_flag(osdc, CEPH_OSDMAP_SORTBITWISE);
        bool recovery_deletes = ceph_osdmap_flag(osdc,
@@ -1584,15 +1584,14 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
                t->osd = acting.primary;
        }
 
-       if (unpaused || legacy_change || force_resend ||
-           (split && con && CEPH_HAVE_FEATURE(con->peer_features,
-                                              RESEND_ON_SPLIT)))
+       if (unpaused || legacy_change || force_resend || split)
                ct_res = CALC_TARGET_NEED_RESEND;
        else
                ct_res = CALC_TARGET_NO_ACTION;
 
 out:
-       dout("%s t %p -> ct_res %d osd %d\n", __func__, t, ct_res, t->osd);
+       dout("%s t %p -> %d%d%d%d ct_res %d osd%d\n", __func__, t, unpaused,
+            legacy_change, force_resend, split, ct_res, t->osd);
        return ct_res;
 }
 
index 0891f49..5156c0e 100644 (file)
@@ -8758,6 +8758,8 @@ int register_netdevice(struct net_device *dev)
        ret = notifier_to_errno(ret);
        if (ret) {
                rollback_registered(dev);
+               rcu_barrier();
+
                dev->reg_state = NETREG_UNREGISTERED;
        }
        /*
index 7878f91..4c6a252 100644 (file)
@@ -8757,13 +8757,13 @@ sk_reuseport_is_valid_access(int off, int size,
                return size == size_default;
 
        /* Fields that allow narrowing */
-       case offsetof(struct sk_reuseport_md, eth_protocol):
+       case bpf_ctx_range(struct sk_reuseport_md, eth_protocol):
                if (size < FIELD_SIZEOF(struct sk_buff, protocol))
                        return false;
                /* fall through */
-       case offsetof(struct sk_reuseport_md, ip_protocol):
-       case offsetof(struct sk_reuseport_md, bind_inany):
-       case offsetof(struct sk_reuseport_md, len):
+       case bpf_ctx_range(struct sk_reuseport_md, ip_protocol):
+       case bpf_ctx_range(struct sk_reuseport_md, bind_inany):
+       case bpf_ctx_range(struct sk_reuseport_md, len):
                bpf_ctx_record_field_size(info, size_default);
                return bpf_ctx_narrow_access_ok(off, size, size_default);
 
index 3e6fedb..2470b4b 100644 (file)
@@ -142,8 +142,8 @@ int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr)
                mutex_unlock(&flow_dissector_mutex);
                return -ENOENT;
        }
-       bpf_prog_put(attached);
        RCU_INIT_POINTER(net->flow_dissector_prog, NULL);
+       bpf_prog_put(attached);
        mutex_unlock(&flow_dissector_mutex);
        return 0;
 }
index 2cf27da..849380a 100644 (file)
@@ -122,7 +122,7 @@ static void queue_process(struct work_struct *work)
                txq = netdev_get_tx_queue(dev, q_index);
                HARD_TX_LOCK(dev, txq, smp_processor_id());
                if (netif_xmit_frozen_or_stopped(txq) ||
-                   netpoll_start_xmit(skb, dev, txq) != NETDEV_TX_OK) {
+                   !dev_xmit_complete(netpoll_start_xmit(skb, dev, txq))) {
                        skb_queue_head(&npinfo->txq, skb);
                        HARD_TX_UNLOCK(dev, txq);
                        local_irq_restore(flags);
@@ -335,7 +335,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
 
                                HARD_TX_UNLOCK(dev, txq);
 
-                               if (status == NETDEV_TX_OK)
+                               if (dev_xmit_complete(status))
                                        break;
 
                        }
@@ -352,7 +352,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
 
        }
 
-       if (status != NETDEV_TX_OK) {
+       if (!dev_xmit_complete(status)) {
                skb_queue_tail(&npinfo->txq, skb);
                schedule_delayed_work(&npinfo->tx_work,0);
        }
index 0338820..982d8d1 100644 (file)
@@ -3664,6 +3664,25 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
        int pos;
        int dummy;
 
+       if (list_skb && !list_skb->head_frag && skb_headlen(list_skb) &&
+           (skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY)) {
+               /* gso_size is untrusted, and we have a frag_list with a linear
+                * non head_frag head.
+                *
+                * (we assume checking the first list_skb member suffices;
+                * i.e if either of the list_skb members have non head_frag
+                * head, then the first one has too).
+                *
+                * If head_skb's headlen does not fit requested gso_size, it
+                * means that the frag_list members do NOT terminate on exact
+                * gso_size boundaries. Hence we cannot perform skb_frag_t page
+                * sharing. Therefore we must fallback to copying the frag_list
+                * skbs; we do so by disabling SG.
+                */
+               if (mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb))
+                       features &= ~NETIF_F_SG;
+       }
+
        __skb_push(head_skb, doffset);
        proto = skb_network_protocol(head_skb, &dummy);
        if (unlikely(!proto))
index d57b0cc..545fac1 100644 (file)
@@ -1992,6 +1992,19 @@ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
 }
 EXPORT_SYMBOL(skb_set_owner_w);
 
+static bool can_skb_orphan_partial(const struct sk_buff *skb)
+{
+#ifdef CONFIG_TLS_DEVICE
+       /* Drivers depend on in-order delivery for crypto offload,
+        * partial orphan breaks out-of-order-OK logic.
+        */
+       if (skb->decrypted)
+               return false;
+#endif
+       return (skb->destructor == sock_wfree ||
+               (IS_ENABLED(CONFIG_INET) && skb->destructor == tcp_wfree));
+}
+
 /* This helper is used by netem, as it can hold packets in its
  * delay queue. We want to allow the owner socket to send more
  * packets, as if they were already TX completed by a typical driver.
@@ -2003,11 +2016,7 @@ void skb_orphan_partial(struct sk_buff *skb)
        if (skb_is_tcp_pure_ack(skb))
                return;
 
-       if (skb->destructor == sock_wfree
-#ifdef CONFIG_INET
-           || skb->destructor == tcp_wfree
-#endif
-               ) {
+       if (can_skb_orphan_partial(skb)) {
                struct sock *sk = skb->sk;
 
                if (refcount_inc_not_zero(&sk->sk_refcnt)) {
@@ -3278,16 +3287,17 @@ static __init int net_inuse_init(void)
 
 core_initcall(net_inuse_init);
 
-static void assign_proto_idx(struct proto *prot)
+static int assign_proto_idx(struct proto *prot)
 {
        prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR);
 
        if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) {
                pr_err("PROTO_INUSE_NR exhausted\n");
-               return;
+               return -ENOSPC;
        }
 
        set_bit(prot->inuse_idx, proto_inuse_idx);
+       return 0;
 }
 
 static void release_proto_idx(struct proto *prot)
@@ -3296,8 +3306,9 @@ static void release_proto_idx(struct proto *prot)
                clear_bit(prot->inuse_idx, proto_inuse_idx);
 }
 #else
-static inline void assign_proto_idx(struct proto *prot)
+static inline int assign_proto_idx(struct proto *prot)
 {
+       return 0;
 }
 
 static inline void release_proto_idx(struct proto *prot)
@@ -3346,6 +3357,8 @@ static int req_prot_init(const struct proto *prot)
 
 int proto_register(struct proto *prot, int alloc_slab)
 {
+       int ret = -ENOBUFS;
+
        if (alloc_slab) {
                prot->slab = kmem_cache_create_usercopy(prot->name,
                                        prot->obj_size, 0,
@@ -3382,20 +3395,27 @@ int proto_register(struct proto *prot, int alloc_slab)
        }
 
        mutex_lock(&proto_list_mutex);
+       ret = assign_proto_idx(prot);
+       if (ret) {
+               mutex_unlock(&proto_list_mutex);
+               goto out_free_timewait_sock_slab_name;
+       }
        list_add(&prot->node, &proto_list);
-       assign_proto_idx(prot);
        mutex_unlock(&proto_list_mutex);
-       return 0;
+       return ret;
 
 out_free_timewait_sock_slab_name:
-       kfree(prot->twsk_prot->twsk_slab_name);
+       if (alloc_slab && prot->twsk_prot)
+               kfree(prot->twsk_prot->twsk_slab_name);
 out_free_request_sock_slab:
-       req_prot_cleanup(prot->rsk_prot);
+       if (alloc_slab) {
+               req_prot_cleanup(prot->rsk_prot);
 
-       kmem_cache_destroy(prot->slab);
-       prot->slab = NULL;
+               kmem_cache_destroy(prot->slab);
+               prot->slab = NULL;
+       }
 out:
-       return -ENOBUFS;
+       return ret;
 }
 EXPORT_SYMBOL(proto_register);
 
index 3312a58..c13ffbd 100644 (file)
@@ -19,6 +19,7 @@ static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
 static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 static struct workqueue_struct *broadcast_wq;
+static atomic64_t cookie_gen;
 
 u64 sock_gen_cookie(struct sock *sk)
 {
@@ -27,7 +28,7 @@ u64 sock_gen_cookie(struct sock *sk)
 
                if (res)
                        return res;
-               res = atomic64_inc_return(&sock_net(sk)->cookie_gen);
+               res = atomic64_inc_return(&cookie_gen);
                atomic64_cmpxchg(&sk->sk_cookie, 0, res);
        }
 }
index 1330a74..50916f9 100644 (file)
@@ -656,6 +656,7 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
                                   struct sock *sk, u64 flags)
 {
        struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        u32 key_size = map->key_size, hash;
        struct bpf_htab_elem *elem, *elem_new;
        struct bpf_htab_bucket *bucket;
@@ -666,6 +667,8 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
        WARN_ON_ONCE(!rcu_read_lock_held());
        if (unlikely(flags > BPF_EXIST))
                return -EINVAL;
+       if (unlikely(icsk->icsk_ulp_data))
+               return -EINVAL;
 
        link = sk_psock_init_link();
        if (!link)
index e94bb02..4f1d4aa 100644 (file)
@@ -120,7 +120,6 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
        int err = 0;
        long vm_wait = 0;
        long current_timeo = *timeo_p;
-       bool noblock = (*timeo_p ? false : true);
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        if (sk_stream_memory_free(sk))
@@ -133,11 +132,8 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
 
                if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                        goto do_error;
-               if (!*timeo_p) {
-                       if (noblock)
-                               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
-                       goto do_nonblock;
-               }
+               if (!*timeo_p)
+                       goto do_eagain;
                if (signal_pending(current))
                        goto do_interrupted;
                sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
@@ -169,7 +165,13 @@ out:
 do_error:
        err = -EPIPE;
        goto out;
-do_nonblock:
+do_eagain:
+       /* Make sure that whenever EAGAIN is returned, EPOLLOUT event can
+        * be generated later.
+        * When TCP receives ACK packets that make room, tcp_check_space()
+        * only calls tcp_new_space() if SOCK_NOSPACE is set.
+        */
+       set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
        err = -EAGAIN;
        goto out;
 do_interrupted:
index 4ec5b7f..09d9286 100644 (file)
@@ -153,6 +153,9 @@ static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds,
 {
        int port;
 
+       if (!ds->ops->port_mdb_add)
+               return;
+
        for_each_set_bit(port, bitmap, ds->num_ports)
                ds->ops->port_mdb_add(ds, port, mdb);
 }
index 6ebbd79..67a1bc6 100644 (file)
@@ -28,6 +28,7 @@
  *
  * RSV - VID[9]:
  *     To be used for further expansion of SWITCH_ID or for other purposes.
+ *     Must be transmitted as zero and ignored on receive.
  *
  * SWITCH_ID - VID[8:6]:
  *     Index of switch within DSA tree. Must be between 0 and
@@ -35,6 +36,7 @@
  *
  * RSV - VID[5:4]:
  *     To be used for further expansion of PORT or for other purposes.
+ *     Must be transmitted as zero and ignored on receive.
  *
  * PORT - VID[3:0]:
  *     Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1.
index e4aba5d..bbe9b3b 100644 (file)
@@ -170,7 +170,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *skb,
        reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail);
        if (!reasm_data)
                goto out_oom;
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, false);
 
        skb->dev = ldev;
        skb->tstamp = fq->q.stamp;
index dacbd58..badc5cf 100644 (file)
@@ -1092,7 +1092,7 @@ static struct packet_type ieee802154_packet_type = {
 
 static int __init af_ieee802154_init(void)
 {
-       int rc = -EINVAL;
+       int rc;
 
        rc = proto_register(&ieee802154_raw_prot, 1);
        if (rc)
index 2db089e..0913a09 100644 (file)
@@ -1582,7 +1582,7 @@ failure:
 }
 
 int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
-                    unsigned char *flags, bool skip_oif)
+                    u8 rt_family, unsigned char *flags, bool skip_oif)
 {
        if (nhc->nhc_flags & RTNH_F_DEAD)
                *flags |= RTNH_F_DEAD;
@@ -1613,7 +1613,7 @@ int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nhc,
                /* if gateway family does not match nexthop family
                 * gateway is encoded as RTA_VIA
                 */
-               if (nhc->nhc_gw_family != nhc->nhc_family) {
+               if (rt_family != nhc->nhc_gw_family) {
                        int alen = sizeof(struct in6_addr);
                        struct nlattr *nla;
                        struct rtvia *via;
@@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(fib_nexthop_info);
 
 #if IS_ENABLED(CONFIG_IP_ROUTE_MULTIPATH) || IS_ENABLED(CONFIG_IPV6)
 int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
-                   int nh_weight)
+                   int nh_weight, u8 rt_family)
 {
        const struct net_device *dev = nhc->nhc_dev;
        struct rtnexthop *rtnh;
@@ -1667,7 +1667,7 @@ int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nhc,
        rtnh->rtnh_hops = nh_weight - 1;
        rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
 
-       if (fib_nexthop_info(skb, nhc, &flags, true) < 0)
+       if (fib_nexthop_info(skb, nhc, rt_family, &flags, true) < 0)
                goto nla_put_failure;
 
        rtnh->rtnh_flags = flags;
@@ -1693,13 +1693,14 @@ static int fib_add_multipath(struct sk_buff *skb, struct fib_info *fi)
                goto nla_put_failure;
 
        if (unlikely(fi->nh)) {
-               if (nexthop_mpath_fill_node(skb, fi->nh) < 0)
+               if (nexthop_mpath_fill_node(skb, fi->nh, AF_INET) < 0)
                        goto nla_put_failure;
                goto mp_end;
        }
 
        for_nexthops(fi) {
-               if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight) < 0)
+               if (fib_add_nexthop(skb, &nh->nh_common, nh->fib_nh_weight,
+                                   AF_INET) < 0)
                        goto nla_put_failure;
 #ifdef CONFIG_IP_ROUTE_CLASSID
                if (nh->nh_tclassid &&
@@ -1775,7 +1776,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
                const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
                unsigned char flags = 0;
 
-               if (fib_nexthop_info(skb, nhc, &flags, false) < 0)
+               if (fib_nexthop_info(skb, nhc, AF_INET, &flags, false) < 0)
                        goto nla_put_failure;
 
                rtm->rtm_flags = flags;
index 2b2b3d2..1ab2fb6 100644 (file)
@@ -2145,7 +2145,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
 
                if (filter->dump_exceptions) {
                        err = fib_dump_info_fnhe(skb, cb, tb->tb_id, fi,
-                                                &i_fa, s_fa);
+                                                &i_fa, s_fa, flags);
                        if (err < 0)
                                goto stop;
                }
index 1510e95..4298aae 100644 (file)
@@ -582,7 +582,13 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
 
        if (!rt)
                goto out;
-       net = dev_net(rt->dst.dev);
+
+       if (rt->dst.dev)
+               net = dev_net(rt->dst.dev);
+       else if (skb_in->dev)
+               net = dev_net(skb_in->dev);
+       else
+               goto out;
 
        /*
         *      Find the original header. It is expected to be valid, of course.
@@ -902,7 +908,7 @@ static bool icmp_redirect(struct sk_buff *skb)
                return false;
        }
 
-       icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway);
+       icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway));
        return true;
 }
 
index 180f689..480d0b2 100644 (file)
@@ -1475,7 +1475,7 @@ EXPORT_SYMBOL(__ip_mc_inc_group);
 
 void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 {
-       __ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE);
+       __ip_mc_inc_group(in_dev, addr, GFP_KERNEL);
 }
 EXPORT_SYMBOL(ip_mc_inc_group);
 
@@ -2197,7 +2197,7 @@ static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
        iml->sflist = NULL;
        iml->sfmode = mode;
        rcu_assign_pointer(inet->mc_list, iml);
-       __ip_mc_inc_group(in_dev, addr, mode);
+       ____ip_mc_inc_group(in_dev, addr, mode, GFP_KERNEL);
        err = 0;
 done:
        return err;
index a999451..10d3173 100644 (file)
@@ -475,11 +475,12 @@ void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
 EXPORT_SYMBOL(inet_frag_reasm_prepare);
 
 void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
-                           void *reasm_data)
+                           void *reasm_data, bool try_coalesce)
 {
        struct sk_buff **nextp = (struct sk_buff **)reasm_data;
        struct rb_node *rbn;
        struct sk_buff *fp;
+       int sum_truesize;
 
        skb_push(head, head->data - skb_network_header(head));
 
@@ -487,25 +488,41 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
        fp = FRAG_CB(head)->next_frag;
        rbn = rb_next(&head->rbnode);
        rb_erase(&head->rbnode, &q->rb_fragments);
+
+       sum_truesize = head->truesize;
        while (rbn || fp) {
                /* fp points to the next sk_buff in the current run;
                 * rbn points to the next run.
                 */
                /* Go through the current run. */
                while (fp) {
-                       *nextp = fp;
-                       nextp = &fp->next;
-                       fp->prev = NULL;
-                       memset(&fp->rbnode, 0, sizeof(fp->rbnode));
-                       fp->sk = NULL;
-                       head->data_len += fp->len;
-                       head->len += fp->len;
+                       struct sk_buff *next_frag = FRAG_CB(fp)->next_frag;
+                       bool stolen;
+                       int delta;
+
+                       sum_truesize += fp->truesize;
                        if (head->ip_summed != fp->ip_summed)
                                head->ip_summed = CHECKSUM_NONE;
                        else if (head->ip_summed == CHECKSUM_COMPLETE)
                                head->csum = csum_add(head->csum, fp->csum);
-                       head->truesize += fp->truesize;
-                       fp = FRAG_CB(fp)->next_frag;
+
+                       if (try_coalesce && skb_try_coalesce(head, fp, &stolen,
+                                                            &delta)) {
+                               kfree_skb_partial(fp, stolen);
+                       } else {
+                               fp->prev = NULL;
+                               memset(&fp->rbnode, 0, sizeof(fp->rbnode));
+                               fp->sk = NULL;
+
+                               head->data_len += fp->len;
+                               head->len += fp->len;
+                               head->truesize += fp->truesize;
+
+                               *nextp = fp;
+                               nextp = &fp->next;
+                       }
+
+                       fp = next_frag;
                }
                /* Move to the next run. */
                if (rbn) {
@@ -516,7 +533,7 @@ void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
                        rbn = rbnext;
                }
        }
-       sub_frag_mem_limit(q->fqdir, head->truesize);
+       sub_frag_mem_limit(q->fqdir, sum_truesize);
 
        *nextp = NULL;
        skb_mark_not_on_list(head);
index 4385eb9..cfeb889 100644 (file)
@@ -393,6 +393,11 @@ err:
        return err;
 }
 
+static bool ip_frag_coalesce_ok(const struct ipq *qp)
+{
+       return qp->q.key.v4.user == IP_DEFRAG_LOCAL_DELIVER;
+}
+
 /* Build a new IP datagram from all its fragments. */
 static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
                         struct sk_buff *prev_tail, struct net_device *dev)
@@ -421,7 +426,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
        if (len > 65535)
                goto out_oversize;
 
-       inet_frag_reasm_finish(&qp->q, skb, reasm_data);
+       inet_frag_reasm_finish(&qp->q, skb, reasm_data,
+                              ip_frag_coalesce_ok(qp));
 
        skb->dev = dev;
        IPCB(skb)->frag_max_size = max(qp->max_df_size, qp->q.max_size);
index 517300d..b6a6f18 100644 (file)
@@ -2728,7 +2728,8 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
 /* called with rcu_read_lock held */
 static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
                        struct rtable *rt, u32 table_id, struct flowi4 *fl4,
-                       struct sk_buff *skb, u32 portid, u32 seq)
+                       struct sk_buff *skb, u32 portid, u32 seq,
+                       unsigned int flags)
 {
        struct rtmsg *r;
        struct nlmsghdr *nlh;
@@ -2736,7 +2737,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
        u32 error;
        u32 metrics[RTAX_MAX];
 
-       nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*r), 0);
+       nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*r), flags);
        if (!nlh)
                return -EMSGSIZE;
 
@@ -2860,7 +2861,7 @@ nla_put_failure:
 static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
                            struct netlink_callback *cb, u32 table_id,
                            struct fnhe_hash_bucket *bucket, int genid,
-                           int *fa_index, int fa_start)
+                           int *fa_index, int fa_start, unsigned int flags)
 {
        int i;
 
@@ -2891,7 +2892,7 @@ static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
                        err = rt_fill_info(net, fnhe->fnhe_daddr, 0, rt,
                                           table_id, NULL, skb,
                                           NETLINK_CB(cb->skb).portid,
-                                          cb->nlh->nlmsg_seq);
+                                          cb->nlh->nlmsg_seq, flags);
                        if (err)
                                return err;
 next:
@@ -2904,7 +2905,7 @@ next:
 
 int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
                       u32 table_id, struct fib_info *fi,
-                      int *fa_index, int fa_start)
+                      int *fa_index, int fa_start, unsigned int flags)
 {
        struct net *net = sock_net(cb->skb->sk);
        int nhsel, genid = fnhe_genid(net);
@@ -2922,7 +2923,8 @@ int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
                err = 0;
                if (bucket)
                        err = fnhe_dump_bucket(net, skb, cb, table_id, bucket,
-                                              genid, fa_index, fa_start);
+                                              genid, fa_index, fa_start,
+                                              flags);
                rcu_read_unlock();
                if (err)
                        return err;
@@ -3183,7 +3185,8 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
                                    fl4.flowi4_tos, res.fi, 0);
        } else {
                err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb,
-                                  NETLINK_CB(in_skb).portid, nlh->nlmsg_seq);
+                                  NETLINK_CB(in_skb).portid,
+                                  nlh->nlmsg_seq, 0);
        }
        if (err < 0)
                goto errout_rcu;
index 7769058..6108206 100644 (file)
@@ -935,6 +935,22 @@ static int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
        return mss_now;
 }
 
+/* In some cases, both sendpage() and sendmsg() could have added
+ * an skb to the write queue, but failed adding payload on it.
+ * We need to remove it to consume less memory, but more
+ * importantly be able to generate EPOLLOUT for Edge Trigger epoll()
+ * users.
+ */
+static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (skb && !skb->len) {
+               tcp_unlink_write_queue(skb, sk);
+               if (tcp_write_queue_empty(sk))
+                       tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
+               sk_wmem_free_skb(sk, skb);
+       }
+}
+
 ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
                         size_t size, int flags)
 {
@@ -984,6 +1000,9 @@ new_segment:
                        if (!skb)
                                goto wait_for_memory;
 
+#ifdef CONFIG_TLS_DEVICE
+                       skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED);
+#endif
                        skb_entail(sk, skb);
                        copy = size_goal;
                }
@@ -1061,6 +1080,7 @@ out:
        return copied;
 
 do_error:
+       tcp_remove_empty_skb(sk, tcp_write_queue_tail(sk));
        if (copied)
                goto out;
 out_err:
@@ -1385,18 +1405,11 @@ out_nopush:
        sock_zerocopy_put(uarg);
        return copied + copied_syn;
 
+do_error:
+       skb = tcp_write_queue_tail(sk);
 do_fault:
-       if (!skb->len) {
-               tcp_unlink_write_queue(skb, sk);
-               /* It is the one place in all of TCP, except connection
-                * reset, where we can be unlinking the send_head.
-                */
-               if (tcp_write_queue_empty(sk))
-                       tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
-               sk_wmem_free_skb(sk, skb);
-       }
+       tcp_remove_empty_skb(sk, skb);
 
-do_error:
        if (copied + copied_syn)
                goto out;
 out_err:
index 3d1e154..8a56e09 100644 (file)
@@ -398,10 +398,14 @@ more_data:
 static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 {
        struct sk_msg tmp, *msg_tx = NULL;
-       int flags = msg->msg_flags | MSG_NO_SHARED_FRAGS;
        int copied = 0, err = 0;
        struct sk_psock *psock;
        long timeo;
+       int flags;
+
+       /* Don't let internal do_tcp_sendpages() flags through */
+       flags = (msg->msg_flags & ~MSG_SENDPAGE_DECRYPTED);
+       flags |= MSG_NO_SHARED_FRAGS;
 
        psock = sk_psock_get(sk);
        if (unlikely(!psock))
index c21e8a2..8a1cd93 100644 (file)
@@ -266,7 +266,7 @@ static void tcp_ecn_accept_cwr(struct sock *sk, const struct sk_buff *skb)
 
 static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp)
 {
-       tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
+       tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
 }
 
 static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb)
index 6e4afc4..8a645f3 100644 (file)
@@ -1320,6 +1320,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
        buff = sk_stream_alloc_skb(sk, nsize, gfp, true);
        if (!buff)
                return -ENOMEM; /* We'll just try again later. */
+       skb_copy_decrypted(buff, skb);
 
        sk->sk_wmem_queued += buff->truesize;
        sk_mem_charge(sk, buff->truesize);
@@ -1874,6 +1875,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
        buff = sk_stream_alloc_skb(sk, 0, gfp, true);
        if (unlikely(!buff))
                return -ENOMEM;
+       skb_copy_decrypted(buff, skb);
 
        sk->sk_wmem_queued += buff->truesize;
        sk_mem_charge(sk, buff->truesize);
@@ -2051,7 +2053,7 @@ static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len)
                if (len <= skb->len)
                        break;
 
-               if (unlikely(TCP_SKB_CB(skb)->eor))
+               if (unlikely(TCP_SKB_CB(skb)->eor) || tcp_has_tx_tstamp(skb))
                        return false;
 
                len -= skb->len;
@@ -2143,6 +2145,7 @@ static int tcp_mtu_probe(struct sock *sk)
        sk_mem_charge(sk, nskb->truesize);
 
        skb = tcp_send_head(sk);
+       skb_copy_decrypted(nskb, skb);
 
        TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
        TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
@@ -2167,6 +2170,7 @@ static int tcp_mtu_probe(struct sock *sk)
                         * we need to propagate it to the new skb.
                         */
                        TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor;
+                       tcp_skb_collapse_tstamp(nskb, skb);
                        tcp_unlink_write_queue(skb, sk);
                        sk_wmem_free_skb(sk, skb);
                } else {
index dc73888..6a576ff 100644 (file)
@@ -478,7 +478,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
        if (!idev) {
                idev = ipv6_add_dev(dev);
                if (IS_ERR(idev))
-                       return NULL;
+                       return idev;
        }
 
        if (dev->flags&IFF_UP)
@@ -1045,7 +1045,8 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
        int err = 0;
 
        if (addr_type == IPV6_ADDR_ANY ||
-           addr_type & IPV6_ADDR_MULTICAST ||
+           (addr_type & IPV6_ADDR_MULTICAST &&
+            !(cfg->ifa_flags & IFA_F_MCAUTOJOIN)) ||
            (!(idev->dev->flags & IFF_LOOPBACK) &&
             !netif_is_l3_master(idev->dev) &&
             addr_type & IPV6_ADDR_LOOPBACK))
@@ -2465,8 +2466,8 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
        ASSERT_RTNL();
 
        idev = ipv6_find_idev(dev);
-       if (!idev)
-               return ERR_PTR(-ENOBUFS);
+       if (IS_ERR(idev))
+               return idev;
 
        if (idev->cnf.disable_ipv6)
                return ERR_PTR(-EACCES);
@@ -3158,7 +3159,7 @@ static void init_loopback(struct net_device *dev)
        ASSERT_RTNL();
 
        idev = ipv6_find_idev(dev);
-       if (!idev) {
+       if (IS_ERR(idev)) {
                pr_debug("%s: add_dev failed\n", __func__);
                return;
        }
@@ -3373,7 +3374,7 @@ static void addrconf_sit_config(struct net_device *dev)
         */
 
        idev = ipv6_find_idev(dev);
-       if (!idev) {
+       if (IS_ERR(idev)) {
                pr_debug("%s: add_dev failed\n", __func__);
                return;
        }
@@ -3398,7 +3399,7 @@ static void addrconf_gre_config(struct net_device *dev)
        ASSERT_RTNL();
 
        idev = ipv6_find_idev(dev);
-       if (!idev) {
+       if (IS_ERR(idev)) {
                pr_debug("%s: add_dev failed\n", __func__);
                return;
        }
@@ -4772,8 +4773,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
                         IFA_F_MCAUTOJOIN | IFA_F_OPTIMISTIC;
 
        idev = ipv6_find_idev(dev);
-       if (!idev)
-               return -ENOBUFS;
+       if (IS_ERR(idev))
+               return PTR_ERR(idev);
 
        if (!ipv6_allow_optimistic_dad(net, idev))
                cfg.ifa_flags &= ~IFA_F_OPTIMISTIC;
index 7f3f13c..eaa4c2c 100644 (file)
@@ -787,14 +787,15 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
        if (pmc) {
                im->idev = pmc->idev;
                if (im->mca_sfmode == MCAST_INCLUDE) {
-                       im->mca_tomb = pmc->mca_tomb;
-                       im->mca_sources = pmc->mca_sources;
+                       swap(im->mca_tomb, pmc->mca_tomb);
+                       swap(im->mca_sources, pmc->mca_sources);
                        for (psf = im->mca_sources; psf; psf = psf->sf_next)
                                psf->sf_crcount = idev->mc_qrv;
                } else {
                        im->mca_crcount = idev->mc_qrv;
                }
                in6_dev_put(pmc->idev);
+               ip6_mc_clear_src(pmc);
                kfree(pmc);
        }
        spin_unlock_bh(&im->mca_lock);
index 0f82c15..fed9666 100644 (file)
@@ -348,7 +348,7 @@ static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
 
        skb_reset_transport_header(skb);
 
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, false);
 
        skb->ignore_df = 1;
        skb->dev = dev;
index 87d2d8c..98ac32b 100644 (file)
@@ -223,7 +223,7 @@ static int __net_init ping_v6_proc_init_net(struct net *net)
        return 0;
 }
 
-static void __net_init ping_v6_proc_exit_net(struct net *net)
+static void __net_exit ping_v6_proc_exit_net(struct net *net)
 {
        remove_proc_entry("icmp6", net->proc_net);
 }
index ca05b16..1f5d4d1 100644 (file)
@@ -282,7 +282,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
 
        skb_reset_transport_header(skb);
 
-       inet_frag_reasm_finish(&fq->q, skb, reasm_data);
+       inet_frag_reasm_finish(&fq->q, skb, reasm_data, true);
 
        skb->dev = dev;
        ipv6_hdr(skb)->payload_len = htons(payload_len);
index fd059e0..546088e 100644 (file)
@@ -4388,13 +4388,14 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
        struct fib6_config cfg = {
                .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
                .fc_ifindex = idev->dev->ifindex,
-               .fc_flags = RTF_UP | RTF_ADDRCONF | RTF_NONEXTHOP,
+               .fc_flags = RTF_UP | RTF_NONEXTHOP,
                .fc_dst = *addr,
                .fc_dst_len = 128,
                .fc_protocol = RTPROT_KERNEL,
                .fc_nlinfo.nl_net = net,
                .fc_ignore_dev_down = true,
        };
+       struct fib6_info *f6i;
 
        if (anycast) {
                cfg.fc_type = RTN_ANYCAST;
@@ -4404,7 +4405,10 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
                cfg.fc_flags |= RTF_LOCAL;
        }
 
-       return ip6_route_info_create(&cfg, gfp_flags, NULL);
+       f6i = ip6_route_info_create(&cfg, gfp_flags, NULL);
+       if (!IS_ERR(f6i))
+               f6i->dst_nocount = true;
+       return f6i;
 }
 
 /* remove deleted ip from prefsrc entries */
@@ -5325,11 +5329,11 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
        if (nexthop_is_multipath(nh)) {
                struct nlattr *mp;
 
-               mp = nla_nest_start(skb, RTA_MULTIPATH);
+               mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
                if (!mp)
                        goto nla_put_failure;
 
-               if (nexthop_mpath_fill_node(skb, nh))
+               if (nexthop_mpath_fill_node(skb, nh, AF_INET6))
                        goto nla_put_failure;
 
                nla_nest_end(skb, mp);
@@ -5337,7 +5341,7 @@ static int rt6_fill_node_nexthop(struct sk_buff *skb, struct nexthop *nh,
                struct fib6_nh *fib6_nh;
 
                fib6_nh = nexthop_fib6_nh(nh);
-               if (fib_nexthop_info(skb, &fib6_nh->nh_common,
+               if (fib_nexthop_info(skb, &fib6_nh->nh_common, AF_INET6,
                                     flags, false) < 0)
                        goto nla_put_failure;
        }
@@ -5466,13 +5470,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
                        goto nla_put_failure;
 
                if (fib_add_nexthop(skb, &rt->fib6_nh->nh_common,
-                                   rt->fib6_nh->fib_nh_weight) < 0)
+                                   rt->fib6_nh->fib_nh_weight, AF_INET6) < 0)
                        goto nla_put_failure;
 
                list_for_each_entry_safe(sibling, next_sibling,
                                         &rt->fib6_siblings, fib6_siblings) {
                        if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
-                                           sibling->fib6_nh->fib_nh_weight) < 0)
+                                           sibling->fib6_nh->fib_nh_weight,
+                                           AF_INET6) < 0)
                                goto nla_put_failure;
                }
 
@@ -5489,7 +5494,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
 
                rtm->rtm_flags |= nh_flags;
        } else {
-               if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common,
+               if (fib_nexthop_info(skb, &rt->fib6_nh->nh_common, AF_INET6,
                                     &nh_flags, false) < 0)
                        goto nla_put_failure;
 
index 4d45806..4105c97 100644 (file)
@@ -1529,7 +1529,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
        int err;
-       int layer2_update;
 
        if (params->vlan) {
                sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
@@ -1546,6 +1545,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (is_multicast_ether_addr(mac))
                return -EINVAL;
 
+       if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER) &&
+           sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !sdata->u.mgd.associated)
+               return -EINVAL;
+
        sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
        if (!sta)
                return -ENOMEM;
@@ -1553,10 +1557,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
                sta->sta.tdls = true;
 
-       if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION &&
-           !sdata->u.mgd.associated)
-               return -EINVAL;
-
        err = sta_apply_parameters(local, sta, params);
        if (err) {
                sta_info_free(local, sta);
@@ -1572,18 +1572,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
            test_sta_flag(sta, WLAN_STA_ASSOC))
                rate_control_rate_init(sta);
 
-       layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-               sdata->vif.type == NL80211_IFTYPE_AP;
-
        err = sta_info_insert_rcu(sta);
        if (err) {
                rcu_read_unlock();
                return err;
        }
 
-       if (layer2_update)
-               cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
-
        rcu_read_unlock();
 
        return 0;
@@ -1681,10 +1675,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                sta->sdata = vlansdata;
                ieee80211_check_fast_xmit(sta);
 
-               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
                        ieee80211_vif_inc_num_mcast(sta->sdata);
-
-               cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
+                       cfg80211_send_layer2_update(sta->sdata->dev,
+                                                   sta->sta.addr);
+               }
        }
 
        err = sta_apply_parameters(local, sta, params);
index 3c1ab87..768d14c 100644 (file)
@@ -2447,11 +2447,13 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
                      skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) &&
                     sdata->control_port_over_nl80211)) {
                struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-               bool noencrypt = status->flag & RX_FLAG_DECRYPTED;
+               bool noencrypt = !(status->flag & RX_FLAG_DECRYPTED);
 
                cfg80211_rx_control_port(dev, skb, noencrypt);
                dev_kfree_skb(skb);
        } else {
+               memset(skb->cb, 0, sizeof(skb->cb));
+
                /* deliver to local stack */
                if (rx->napi)
                        napi_gro_receive(rx->napi, skb);
@@ -2546,8 +2548,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 
        if (skb) {
                skb->protocol = eth_type_trans(skb, dev);
-               memset(skb->cb, 0, sizeof(skb->cb));
-
                ieee80211_deliver_skb_to_local_stack(skb, rx);
        }
 
index 95eb822..5fb368c 100644 (file)
@@ -1979,6 +1979,10 @@ int sta_info_move_state(struct sta_info *sta,
                        ieee80211_check_fast_xmit(sta);
                        ieee80211_check_fast_rx(sta);
                }
+               if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sta->sdata->vif.type == NL80211_IFTYPE_AP)
+                       cfg80211_send_layer2_update(sta->sdata->dev,
+                                                   sta->sta.addr);
                break;
        default:
                break;
index d25e91d..44b6750 100644 (file)
@@ -133,12 +133,12 @@ static int mpls_xmit(struct sk_buff *skb)
        mpls_stats_inc_outucastpkts(out_dev, skb);
 
        if (rt) {
-               if (rt->rt_gw_family == AF_INET)
-                       err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
-                                        skb);
-               else if (rt->rt_gw_family == AF_INET6)
+               if (rt->rt_gw_family == AF_INET6)
                        err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt->rt_gw6,
                                         skb);
+               else
+                       err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
+                                        skb);
        } else if (rt6) {
                if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
                        /* 6PE (RFC 4798) */
index 5c3fad8..0187e65 100644 (file)
@@ -54,7 +54,7 @@ static void ncsi_cmd_build_header(struct ncsi_pkt_hdr *h,
        checksum = ncsi_calculate_checksum((unsigned char *)h,
                                           sizeof(*h) + nca->payload);
        pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) +
-                   nca->payload);
+                   ALIGN(nca->payload, 4));
        *pchecksum = htonl(checksum);
 }
 
@@ -309,14 +309,21 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
 
 int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
 {
+       struct ncsi_cmd_handler *nch = NULL;
        struct ncsi_request *nr;
+       unsigned char type;
        struct ethhdr *eh;
-       struct ncsi_cmd_handler *nch = NULL;
        int i, ret;
 
+       /* Use OEM generic handler for Netlink request */
+       if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
+               type = NCSI_PKT_CMD_OEM;
+       else
+               type = nca->type;
+
        /* Search for the handler */
        for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
-               if (ncsi_cmd_handlers[i].type == nca->type) {
+               if (ncsi_cmd_handlers[i].type == type) {
                        if (ncsi_cmd_handlers[i].handler)
                                nch = &ncsi_cmd_handlers[i];
                        else
index 7581bf9..d876bd5 100644 (file)
@@ -47,7 +47,8 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
        if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
            ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
                netdev_dbg(nr->ndp->ndev.dev,
-                          "NCSI: non zero response/reason code\n");
+                          "NCSI: non zero response/reason code %04xh, %04xh\n",
+                           ntohs(h->code), ntohs(h->reason));
                return -EPERM;
        }
 
@@ -55,7 +56,7 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
         * sender doesn't support checksum according to NCSI
         * specification.
         */
-       pchecksum = (__be32 *)((void *)(h + 1) + payload - 4);
+       pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4);
        if (ntohl(*pchecksum) == 0)
                return 0;
 
@@ -63,7 +64,9 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
                                           sizeof(*h) + payload - 4);
 
        if (*pchecksum != htonl(checksum)) {
-               netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n");
+               netdev_dbg(nr->ndp->ndev.dev,
+                          "NCSI: checksum mismatched; recd: %08x calc: %08x\n",
+                          *pchecksum, htonl(checksum));
                return -EINVAL;
        }
 
index a542761..81a8ef4 100644 (file)
@@ -453,13 +453,12 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
  * table location, we assume id gets exposed to userspace.
  *
  * Following nf_conn items do not change throughout lifetime
- * of the nf_conn after it has been committed to main hash table:
+ * of the nf_conn:
  *
  * 1. nf_conn address
- * 2. nf_conn->ext address
- * 3. nf_conn->master address (normally NULL)
- * 4. tuple
- * 5. the associated net namespace
+ * 2. nf_conn->master address (normally NULL)
+ * 3. the associated net namespace
+ * 4. the original direction tuple
  */
 u32 nf_ct_get_id(const struct nf_conn *ct)
 {
@@ -469,9 +468,10 @@ u32 nf_ct_get_id(const struct nf_conn *ct)
        net_get_random_once(&ct_id_seed, sizeof(ct_id_seed));
 
        a = (unsigned long)ct;
-       b = (unsigned long)ct->master ^ net_hash_mix(nf_ct_net(ct));
-       c = (unsigned long)ct->ext;
-       d = (unsigned long)siphash(&ct->tuplehash, sizeof(ct->tuplehash),
+       b = (unsigned long)ct->master;
+       c = (unsigned long)nf_ct_net(ct);
+       d = (unsigned long)siphash(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+                                  sizeof(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple),
                                   &ct_id_seed);
 #ifdef CONFIG_64BIT
        return siphash_4u64((u64)a, (u64)b, (u64)c, (u64)d, &ct_id_seed);
index 0ecb3e2..8d96738 100644 (file)
@@ -322,7 +322,7 @@ static int find_pattern(const char *data, size_t dlen,
                i++;
        }
 
-       pr_debug("Skipped up to `%c'!\n", skip);
+       pr_debug("Skipped up to 0x%hhx delimiter!\n", skip);
 
        *numoff = i;
        *numlen = getnum(data + i, dlen - i, cmd, term, numoff);
index 6aa01eb..e2d13cd 100644 (file)
@@ -553,10 +553,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
                goto nla_put_failure;
 
        if (ctnetlink_dump_status(skb, ct) < 0 ||
-           ctnetlink_dump_timeout(skb, ct) < 0 ||
            ctnetlink_dump_acct(skb, ct, type) < 0 ||
            ctnetlink_dump_timestamp(skb, ct) < 0 ||
-           ctnetlink_dump_protoinfo(skb, ct) < 0 ||
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
            ctnetlink_dump_secctx(skb, ct) < 0 ||
@@ -568,6 +566,11 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
            ctnetlink_dump_ct_synproxy(skb, ct) < 0)
                goto nla_put_failure;
 
+       if (!test_bit(IPS_OFFLOAD_BIT, &ct->status) &&
+           (ctnetlink_dump_timeout(skb, ct) < 0 ||
+            ctnetlink_dump_protoinfo(skb, ct) < 0))
+               goto nla_put_failure;
+
        nlmsg_end(skb, nlh);
        return skb->len;
 
index e0d392c..0006503 100644 (file)
@@ -1037,8 +1037,13 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
        table[NF_SYSCTL_CT_COUNT].data = &net->ct.count;
        table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum;
        table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid;
+       table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct;
+       table[NF_SYSCTL_CT_HELPER].data = &net->ct.sysctl_auto_assign_helper;
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events;
+#endif
+#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
+       table[NF_SYSCTL_CT_TIMESTAMP].data = &net->ct.sysctl_tstamp;
 #endif
        table[NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC].data = &nf_generic_pernet(net)->timeout;
        table[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP].data = &nf_icmp_pernet(net)->timeout;
index e3d7972..a0b4bf6 100644 (file)
@@ -111,15 +111,16 @@ static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
 #define NF_FLOWTABLE_TCP_PICKUP_TIMEOUT        (120 * HZ)
 #define NF_FLOWTABLE_UDP_PICKUP_TIMEOUT        (30 * HZ)
 
-static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+static inline __s32 nf_flow_timeout_delta(unsigned int timeout)
+{
+       return (__s32)(timeout - (u32)jiffies);
+}
+
+static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
 {
        const struct nf_conntrack_l4proto *l4proto;
+       int l4num = nf_ct_protonum(ct);
        unsigned int timeout;
-       int l4num;
-
-       l4num = nf_ct_protonum(ct);
-       if (l4num == IPPROTO_TCP)
-               flow_offload_fixup_tcp(&ct->proto.tcp);
 
        l4proto = nf_ct_l4proto_find(l4num);
        if (!l4proto)
@@ -132,7 +133,20 @@ static void flow_offload_fixup_ct_state(struct nf_conn *ct)
        else
                return;
 
-       ct->timeout = nfct_time_stamp + timeout;
+       if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
+               ct->timeout = nfct_time_stamp + timeout;
+}
+
+static void flow_offload_fixup_ct_state(struct nf_conn *ct)
+{
+       if (nf_ct_protonum(ct) == IPPROTO_TCP)
+               flow_offload_fixup_tcp(&ct->proto.tcp);
+}
+
+static void flow_offload_fixup_ct(struct nf_conn *ct)
+{
+       flow_offload_fixup_ct_state(ct);
+       flow_offload_fixup_ct_timeout(ct);
 }
 
 void flow_offload_free(struct flow_offload *flow)
@@ -203,11 +217,16 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
                return err;
        }
 
-       flow->timeout = (u32)jiffies;
+       flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
        return 0;
 }
 EXPORT_SYMBOL_GPL(flow_offload_add);
 
+static inline bool nf_flow_has_expired(const struct flow_offload *flow)
+{
+       return nf_flow_timeout_delta(flow->timeout) <= 0;
+}
+
 static void flow_offload_del(struct nf_flowtable *flow_table,
                             struct flow_offload *flow)
 {
@@ -223,6 +242,11 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
        e = container_of(flow, struct flow_offload_entry, flow);
        clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
 
+       if (nf_flow_has_expired(flow))
+               flow_offload_fixup_ct(e->ct);
+       else if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
+               flow_offload_fixup_ct_timeout(e->ct);
+
        flow_offload_free(flow);
 }
 
@@ -298,11 +322,6 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
        return err;
 }
 
-static inline bool nf_flow_has_expired(const struct flow_offload *flow)
-{
-       return (__s32)(flow->timeout - (u32)jiffies) <= 0;
-}
-
 static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
 {
        struct nf_flowtable *flow_table = data;
index cdfc335..b9e7dd6 100644 (file)
@@ -214,6 +214,24 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
        return true;
 }
 
+static int nf_flow_offload_dst_check(struct dst_entry *dst)
+{
+       if (unlikely(dst_xfrm(dst)))
+               return dst_check(dst, 0) ? 0 : -1;
+
+       return 0;
+}
+
+static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
+                                     const struct nf_hook_state *state,
+                                     struct dst_entry *dst)
+{
+       skb_orphan(skb);
+       skb_dst_set_noref(skb, dst);
+       dst_output(state->net, state->sk, skb);
+       return NF_STOLEN;
+}
+
 unsigned int
 nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
                        const struct nf_hook_state *state)
@@ -254,12 +272,25 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
        if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
                return NF_ACCEPT;
 
+       if (nf_flow_offload_dst_check(&rt->dst)) {
+               flow_offload_teardown(flow);
+               return NF_ACCEPT;
+       }
+
        if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
                return NF_DROP;
 
        flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
        iph = ip_hdr(skb);
        ip_decrease_ttl(iph);
+       skb->tstamp = 0;
+
+       if (unlikely(dst_xfrm(&rt->dst))) {
+               memset(skb->cb, 0, sizeof(struct inet_skb_parm));
+               IPCB(skb)->iif = skb->dev->ifindex;
+               IPCB(skb)->flags = IPSKB_FORWARDED;
+               return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+       }
 
        skb->dev = outdev;
        nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
@@ -467,6 +498,11 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
                                sizeof(*ip6h)))
                return NF_ACCEPT;
 
+       if (nf_flow_offload_dst_check(&rt->dst)) {
+               flow_offload_teardown(flow);
+               return NF_ACCEPT;
+       }
+
        if (skb_try_make_writable(skb, sizeof(*ip6h)))
                return NF_DROP;
 
@@ -476,6 +512,14 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
        flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
        ip6h = ipv6_hdr(skb);
        ip6h->hop_limit--;
+       skb->tstamp = 0;
+
+       if (unlikely(dst_xfrm(&rt->dst))) {
+               memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+               IP6CB(skb)->iif = skb->dev->ifindex;
+               IP6CB(skb)->flags = IP6SKB_FORWARDED;
+               return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+       }
 
        skb->dev = outdev;
        nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
index 605a7cf..d47469f 100644 (file)
@@ -138,9 +138,14 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
                return;
 
        list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
-               if (trans->msg_type == NFT_MSG_NEWSET &&
-                   nft_trans_set(trans) == set) {
-                       set->bound = true;
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWSET:
+                       if (nft_trans_set(trans) == set)
+                               nft_trans_set_bound(trans) = true;
+                       break;
+               case NFT_MSG_NEWSETELEM:
+                       if (nft_trans_elem_set(trans) == set)
+                               nft_trans_elem_set_bound(trans) = true;
                        break;
                }
        }
@@ -1662,6 +1667,10 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
 
                chain->flags |= NFT_BASE_CHAIN | flags;
                basechain->policy = NF_ACCEPT;
+               if (chain->flags & NFT_CHAIN_HW_OFFLOAD &&
+                   nft_chain_offload_priority(basechain) < 0)
+                       return -EOPNOTSUPP;
+
                flow_block_init(&basechain->flow_block);
        } else {
                chain = kzalloc(sizeof(*chain), GFP_KERNEL);
@@ -6906,7 +6915,7 @@ static int __nf_tables_abort(struct net *net)
                        break;
                case NFT_MSG_NEWSET:
                        trans->ctx.table->use--;
-                       if (nft_trans_set(trans)->bound) {
+                       if (nft_trans_set_bound(trans)) {
                                nft_trans_destroy(trans);
                                break;
                        }
@@ -6918,7 +6927,7 @@ static int __nf_tables_abort(struct net *net)
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWSETELEM:
-                       if (nft_trans_elem_set(trans)->bound) {
+                       if (nft_trans_elem_set_bound(trans)) {
                                nft_trans_destroy(trans);
                                break;
                        }
index 64f5fd5..c0d18c1 100644 (file)
@@ -103,10 +103,11 @@ void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
 }
 
 static void nft_flow_offload_common_init(struct flow_cls_common_offload *common,
-                                        __be16 proto,
-                                       struct netlink_ext_ack *extack)
+                                        __be16 proto, int priority,
+                                        struct netlink_ext_ack *extack)
 {
        common->protocol = proto;
+       common->prio = priority;
        common->extack = extack;
 }
 
@@ -124,6 +125,15 @@ static int nft_setup_cb_call(struct nft_base_chain *basechain,
        return 0;
 }
 
+int nft_chain_offload_priority(struct nft_base_chain *basechain)
+{
+       if (basechain->ops.priority <= 0 ||
+           basechain->ops.priority > USHRT_MAX)
+               return -1;
+
+       return 0;
+}
+
 static int nft_flow_offload_rule(struct nft_trans *trans,
                                 enum flow_cls_command command)
 {
@@ -142,7 +152,8 @@ static int nft_flow_offload_rule(struct nft_trans *trans,
        if (flow)
                proto = flow->proto;
 
-       nft_flow_offload_common_init(&cls_flow.common, proto, &extack);
+       nft_flow_offload_common_init(&cls_flow.common, proto,
+                                    basechain->ops.priority, &extack);
        cls_flow.command = command;
        cls_flow.cookie = (unsigned long) rule;
        if (flow)
index 2cf3f32..a2e726a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables_core.h>
 #include <net/netfilter/nf_tables.h>
+#include <net/ipv6.h>
 
 #include <net/netfilter/nft_fib.h>
 
@@ -34,6 +35,8 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
                }
                break;
        case ETH_P_IPV6:
+               if (!ipv6_mod_enabled())
+                       break;
                switch (priv->result) {
                case NFT_FIB_RESULT_OIF:
                case NFT_FIB_RESULT_OIFNAME:
index aa5f571..01705ad 100644 (file)
@@ -72,11 +72,11 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 {
        struct nft_flow_offload *priv = nft_expr_priv(expr);
        struct nf_flowtable *flowtable = &priv->flowtable->data;
+       struct tcphdr _tcph, *tcph = NULL;
        enum ip_conntrack_info ctinfo;
        struct nf_flow_route route;
        struct flow_offload *flow;
        enum ip_conntrack_dir dir;
-       bool is_tcp = false;
        struct nf_conn *ct;
        int ret;
 
@@ -89,7 +89,10 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 
        switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
        case IPPROTO_TCP:
-               is_tcp = true;
+               tcph = skb_header_pointer(pkt->skb, pkt->xt.thoff,
+                                         sizeof(_tcph), &_tcph);
+               if (unlikely(!tcph || tcph->fin || tcph->rst))
+                       goto out;
                break;
        case IPPROTO_UDP:
                break;
@@ -115,7 +118,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
        if (!flow)
                goto err_flow_alloc;
 
-       if (is_tcp) {
+       if (tcph) {
                ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
                ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
        }
@@ -146,6 +149,11 @@ static int nft_flow_offload_validate(const struct nft_ctx *ctx,
        return nft_chain_validate_hooks(ctx->chain, hook_mask);
 }
 
+static const struct nla_policy nft_flow_offload_policy[NFTA_FLOW_MAX + 1] = {
+       [NFTA_FLOW_TABLE_NAME]  = { .type = NLA_STRING,
+                                   .len = NFT_NAME_MAXLEN - 1 },
+};
+
 static int nft_flow_offload_init(const struct nft_ctx *ctx,
                                 const struct nft_expr *expr,
                                 const struct nlattr * const tb[])
@@ -204,6 +212,7 @@ static const struct nft_expr_ops nft_flow_offload_ops = {
 static struct nft_expr_type nft_flow_offload_type __read_mostly = {
        .name           = "flow_offload",
        .ops            = &nft_flow_offload_ops,
+       .policy         = nft_flow_offload_policy,
        .maxattr        = NFTA_FLOW_MAX,
        .owner          = THIS_MODULE,
 };
index d7f3776..637ce3e 100644 (file)
@@ -47,9 +47,6 @@ static void nft_socket_eval(const struct nft_expr *expr,
                return;
        }
 
-       /* So that subsequent socket matching not to require other lookups. */
-       skb->sk = sk;
-
        switch(priv->key) {
        case NFT_SOCKET_TRANSPARENT:
                nft_reg_store8(dest, inet_sk_transparent(sk));
@@ -66,6 +63,9 @@ static void nft_socket_eval(const struct nft_expr *expr,
                WARN_ON(1);
                regs->verdict.code = NFT_BREAK;
        }
+
+       if (sk != skb->sk)
+               sock_gen_put(sk);
 }
 
 static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
index d0ab1ad..5aab6df 100644 (file)
@@ -54,25 +54,39 @@ nfacct_mt_destroy(const struct xt_mtdtor_param *par)
        nfnl_acct_put(info->nfacct);
 }
 
-static struct xt_match nfacct_mt_reg __read_mostly = {
-       .name       = "nfacct",
-       .family     = NFPROTO_UNSPEC,
-       .checkentry = nfacct_mt_checkentry,
-       .match      = nfacct_mt,
-       .destroy    = nfacct_mt_destroy,
-       .matchsize  = sizeof(struct xt_nfacct_match_info),
-       .usersize   = offsetof(struct xt_nfacct_match_info, nfacct),
-       .me         = THIS_MODULE,
+static struct xt_match nfacct_mt_reg[] __read_mostly = {
+       {
+               .name       = "nfacct",
+               .revision   = 0,
+               .family     = NFPROTO_UNSPEC,
+               .checkentry = nfacct_mt_checkentry,
+               .match      = nfacct_mt,
+               .destroy    = nfacct_mt_destroy,
+               .matchsize  = sizeof(struct xt_nfacct_match_info),
+               .usersize   = offsetof(struct xt_nfacct_match_info, nfacct),
+               .me         = THIS_MODULE,
+       },
+       {
+               .name       = "nfacct",
+               .revision   = 1,
+               .family     = NFPROTO_UNSPEC,
+               .checkentry = nfacct_mt_checkentry,
+               .match      = nfacct_mt,
+               .destroy    = nfacct_mt_destroy,
+               .matchsize  = sizeof(struct xt_nfacct_match_info_v1),
+               .usersize   = offsetof(struct xt_nfacct_match_info_v1, nfacct),
+               .me         = THIS_MODULE,
+       },
 };
 
 static int __init nfacct_mt_init(void)
 {
-       return xt_register_match(&nfacct_mt_reg);
+       return xt_register_matches(nfacct_mt_reg, ARRAY_SIZE(nfacct_mt_reg));
 }
 
 static void __exit nfacct_mt_exit(void)
 {
-       xt_unregister_match(&nfacct_mt_reg);
+       xt_unregister_matches(nfacct_mt_reg, ARRAY_SIZE(nfacct_mt_reg));
 }
 
 module_init(nfacct_mt_init);
index ead7c60..b92b22c 100644 (file)
@@ -101,11 +101,9 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)
        if (info->bitmask & (XT_PHYSDEV_OP_OUT | XT_PHYSDEV_OP_ISOUT) &&
            (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
             info->invert & XT_PHYSDEV_OP_BRIDGED) &&
-           par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
-           (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
+           par->hook_mask & (1 << NF_INET_LOCAL_OUT)) {
                pr_info_ratelimited("--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\n");
-               if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
-                       return -EINVAL;
+               return -EINVAL;
        }
 
        if (!brnf_probed) {
index 848c6eb..05249eb 100644 (file)
@@ -67,6 +67,7 @@ struct ovs_conntrack_info {
        struct md_mark mark;
        struct md_labels labels;
        char timeout[CTNL_TIMEOUT_NAME_MAX];
+       struct nf_ct_timeout *nf_ct_timeout;
 #if IS_ENABLED(CONFIG_NF_NAT)
        struct nf_nat_range2 range;  /* Only present for SRC NAT and DST NAT. */
 #endif
@@ -524,6 +525,11 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
                return -EPFNOSUPPORT;
        }
 
+       /* The key extracted from the fragment that completed this datagram
+        * likely didn't have an L4 header, so regenerate it.
+        */
+       ovs_flow_key_update_l3l4(skb, key);
+
        key->ip.frag = OVS_FRAG_TYPE_NONE;
        skb_clear_hash(skb);
        skb->ignore_df = 1;
@@ -697,6 +703,14 @@ static bool skb_nfct_cached(struct net *net,
                if (help && rcu_access_pointer(help->helper) != info->helper)
                        return false;
        }
+       if (info->nf_ct_timeout) {
+               struct nf_conn_timeout *timeout_ext;
+
+               timeout_ext = nf_ct_timeout_find(ct);
+               if (!timeout_ext || info->nf_ct_timeout !=
+                   rcu_dereference(timeout_ext->timeout))
+                       return false;
+       }
        /* Force conntrack entry direction to the current packet? */
        if (info->force && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
                /* Delete the conntrack entry if confirmed, else just release
@@ -1565,7 +1579,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                case OVS_CT_ATTR_TIMEOUT:
                        memcpy(info->timeout, nla_data(a), nla_len(a));
                        if (!memchr(info->timeout, '\0', nla_len(a))) {
-                               OVS_NLERR(log, "Invalid conntrack helper");
+                               OVS_NLERR(log, "Invalid conntrack timeout");
                                return -EINVAL;
                        }
                        break;
@@ -1657,6 +1671,10 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
                                      ct_info.timeout))
                        pr_info_ratelimited("Failed to associated timeout "
                                            "policy `%s'\n", ct_info.timeout);
+               else
+                       ct_info.nf_ct_timeout = rcu_dereference(
+                               nf_ct_timeout_find(ct_info.ct)->timeout);
+
        }
 
        if (helper) {
index bc89e16..9d81d2c 100644 (file)
@@ -523,78 +523,15 @@ static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
 }
 
 /**
- * key_extract - extracts a flow key from an Ethernet frame.
+ * key_extract_l3l4 - extracts L3/L4 header information.
  * @skb: sk_buff that contains the frame, with skb->data pointing to the
- * Ethernet header
+ *       L3 header
  * @key: output flow key
  *
- * The caller must ensure that skb->len >= ETH_HLEN.
- *
- * Returns 0 if successful, otherwise a negative errno value.
- *
- * Initializes @skb header fields as follows:
- *
- *    - skb->mac_header: the L2 header.
- *
- *    - skb->network_header: just past the L2 header, or just past the
- *      VLAN header, to the first byte of the L2 payload.
- *
- *    - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6
- *      on output, then just past the IP header, if one is present and
- *      of a correct length, otherwise the same as skb->network_header.
- *      For other key->eth.type values it is left untouched.
- *
- *    - skb->protocol: the type of the data starting at skb->network_header.
- *      Equals to key->eth.type.
  */
-static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
 {
        int error;
-       struct ethhdr *eth;
-
-       /* Flags are always used as part of stats */
-       key->tp.flags = 0;
-
-       skb_reset_mac_header(skb);
-
-       /* Link layer. */
-       clear_vlan(key);
-       if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) {
-               if (unlikely(eth_type_vlan(skb->protocol)))
-                       return -EINVAL;
-
-               skb_reset_network_header(skb);
-               key->eth.type = skb->protocol;
-       } else {
-               eth = eth_hdr(skb);
-               ether_addr_copy(key->eth.src, eth->h_source);
-               ether_addr_copy(key->eth.dst, eth->h_dest);
-
-               __skb_pull(skb, 2 * ETH_ALEN);
-               /* We are going to push all headers that we pull, so no need to
-               * update skb->csum here.
-               */
-
-               if (unlikely(parse_vlan(skb, key)))
-                       return -ENOMEM;
-
-               key->eth.type = parse_ethertype(skb);
-               if (unlikely(key->eth.type == htons(0)))
-                       return -ENOMEM;
-
-               /* Multiple tagged packets need to retain TPID to satisfy
-                * skb_vlan_pop(), which will later shift the ethertype into
-                * skb->protocol.
-                */
-               if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK))
-                       skb->protocol = key->eth.cvlan.tpid;
-               else
-                       skb->protocol = key->eth.type;
-
-               skb_reset_network_header(skb);
-               __skb_push(skb, skb->data - skb_mac_header(skb));
-       }
-       skb_reset_mac_len(skb);
 
        /* Network layer. */
        if (key->eth.type == htons(ETH_P_IP)) {
@@ -623,6 +560,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
                offset = nh->frag_off & htons(IP_OFFSET);
                if (offset) {
                        key->ip.frag = OVS_FRAG_TYPE_LATER;
+                       memset(&key->tp, 0, sizeof(key->tp));
                        return 0;
                }
                if (nh->frag_off & htons(IP_MF) ||
@@ -740,8 +678,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
                        return error;
                }
 
-               if (key->ip.frag == OVS_FRAG_TYPE_LATER)
+               if (key->ip.frag == OVS_FRAG_TYPE_LATER) {
+                       memset(&key->tp, 0, sizeof(key->tp));
                        return 0;
+               }
                if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
                        key->ip.frag = OVS_FRAG_TYPE_FIRST;
 
@@ -788,6 +728,92 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
        return 0;
 }
 
+/**
+ * key_extract - extracts a flow key from an Ethernet frame.
+ * @skb: sk_buff that contains the frame, with skb->data pointing to the
+ * Ethernet header
+ * @key: output flow key
+ *
+ * The caller must ensure that skb->len >= ETH_HLEN.
+ *
+ * Returns 0 if successful, otherwise a negative errno value.
+ *
+ * Initializes @skb header fields as follows:
+ *
+ *    - skb->mac_header: the L2 header.
+ *
+ *    - skb->network_header: just past the L2 header, or just past the
+ *      VLAN header, to the first byte of the L2 payload.
+ *
+ *    - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6
+ *      on output, then just past the IP header, if one is present and
+ *      of a correct length, otherwise the same as skb->network_header.
+ *      For other key->eth.type values it is left untouched.
+ *
+ *    - skb->protocol: the type of the data starting at skb->network_header.
+ *      Equals to key->eth.type.
+ */
+static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
+{
+       struct ethhdr *eth;
+
+       /* Flags are always used as part of stats */
+       key->tp.flags = 0;
+
+       skb_reset_mac_header(skb);
+
+       /* Link layer. */
+       clear_vlan(key);
+       if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) {
+               if (unlikely(eth_type_vlan(skb->protocol)))
+                       return -EINVAL;
+
+               skb_reset_network_header(skb);
+               key->eth.type = skb->protocol;
+       } else {
+               eth = eth_hdr(skb);
+               ether_addr_copy(key->eth.src, eth->h_source);
+               ether_addr_copy(key->eth.dst, eth->h_dest);
+
+               __skb_pull(skb, 2 * ETH_ALEN);
+               /* We are going to push all headers that we pull, so no need to
+                * update skb->csum here.
+                */
+
+               if (unlikely(parse_vlan(skb, key)))
+                       return -ENOMEM;
+
+               key->eth.type = parse_ethertype(skb);
+               if (unlikely(key->eth.type == htons(0)))
+                       return -ENOMEM;
+
+               /* Multiple tagged packets need to retain TPID to satisfy
+                * skb_vlan_pop(), which will later shift the ethertype into
+                * skb->protocol.
+                */
+               if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK))
+                       skb->protocol = key->eth.cvlan.tpid;
+               else
+                       skb->protocol = key->eth.type;
+
+               skb_reset_network_header(skb);
+               __skb_push(skb, skb->data - skb_mac_header(skb));
+       }
+
+       skb_reset_mac_len(skb);
+
+       /* Fill out L3/L4 key info, if any */
+       return key_extract_l3l4(skb, key);
+}
+
+/* In the case of conntrack fragment handling it expects L3 headers,
+ * add a helper.
+ */
+int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
+{
+       return key_extract_l3l4(skb, key);
+}
+
 int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
 {
        int res;
index a5506e2..b830d5f 100644 (file)
@@ -270,6 +270,7 @@ void ovs_flow_stats_clear(struct sw_flow *);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
 int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key);
+int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key);
 int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
                         struct sk_buff *skb,
                         struct sw_flow_key *key);
index 8d54f30..e2742b0 100644 (file)
@@ -2618,6 +2618,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 
        mutex_lock(&po->pg_vec_lock);
 
+       /* packet_sendmsg() check on tx_ring.pg_vec was lockless,
+        * we need to confirm it under protection of pg_vec_lock.
+        */
+       if (unlikely(!po->tx_ring.pg_vec)) {
+               err = -EBUSY;
+               goto out;
+       }
        if (likely(saddr == NULL)) {
                dev     = packet_cached_dev_get(po);
                proto   = po->num;
index 841f198..66e4b61 100644 (file)
@@ -154,7 +154,7 @@ static void psample_group_destroy(struct psample_group *group)
 {
        psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP);
        list_del(&group->list);
-       kfree(group);
+       kfree_rcu(group, rcu);
 }
 
 static struct psample_group *
index ccff1e5..e35869e 100644 (file)
@@ -84,11 +84,14 @@ static ssize_t qrtr_tun_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (!kbuf)
                return -ENOMEM;
 
-       if (!copy_from_iter_full(kbuf, len, from))
+       if (!copy_from_iter_full(kbuf, len, from)) {
+               kfree(kbuf);
                return -EFAULT;
+       }
 
        ret = qrtr_endpoint_post(&tun->ep, kbuf, len);
 
+       kfree(kbuf);
        return ret < 0 ? ret : len;
 }
 
index 0f4398e..05464fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -239,34 +239,30 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        }
 
-       sock_set_flag(sk, SOCK_RCU_FREE);
-       ret = rds_add_bound(rs, binding_addr, &port, scope_id);
-       if (ret)
-               goto out;
-
-       if (rs->rs_transport) { /* previously bound */
+       /* The transport can be set using SO_RDS_TRANSPORT option before the
+        * socket is bound.
+        */
+       if (rs->rs_transport) {
                trans = rs->rs_transport;
                if (trans->laddr_check(sock_net(sock->sk),
                                       binding_addr, scope_id) != 0) {
                        ret = -ENOPROTOOPT;
-                       rds_remove_bound(rs);
-               } else {
-                       ret = 0;
+                       goto out;
                }
-               goto out;
-       }
-       trans = rds_trans_get_preferred(sock_net(sock->sk), binding_addr,
-                                       scope_id);
-       if (!trans) {
-               ret = -EADDRNOTAVAIL;
-               rds_remove_bound(rs);
-               pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
-                                   __func__, binding_addr);
-               goto out;
+       } else {
+               trans = rds_trans_get_preferred(sock_net(sock->sk),
+                                               binding_addr, scope_id);
+               if (!trans) {
+                       ret = -EADDRNOTAVAIL;
+                       pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
+                                           __func__, binding_addr);
+                       goto out;
+               }
+               rs->rs_transport = trans;
        }
 
-       rs->rs_transport = trans;
-       ret = 0;
+       sock_set_flag(sk, SOCK_RCU_FREE);
+       ret = rds_add_bound(rs, binding_addr, &port, scope_id);
 
 out:
        release_sock(sk);
index ec05d91..45acab2 100644 (file)
@@ -291,7 +291,7 @@ static int rds_ib_conn_info_visitor(struct rds_connection *conn,
                                    void *buffer)
 {
        struct rds_info_rdma_connection *iinfo = buffer;
-       struct rds_ib_connection *ic;
+       struct rds_ib_connection *ic = conn->c_transport_data;
 
        /* We will only ever look at IB transports */
        if (conn->c_trans != &rds_ib_transport)
@@ -301,15 +301,16 @@ static int rds_ib_conn_info_visitor(struct rds_connection *conn,
 
        iinfo->src_addr = conn->c_laddr.s6_addr32[3];
        iinfo->dst_addr = conn->c_faddr.s6_addr32[3];
-       iinfo->tos = conn->c_tos;
+       if (ic) {
+               iinfo->tos = conn->c_tos;
+               iinfo->sl = ic->i_sl;
+       }
 
        memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
        memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
        if (rds_conn_state(conn) == RDS_CONN_UP) {
                struct rds_ib_device *rds_ibdev;
 
-               ic = conn->c_transport_data;
-
                rdma_read_gids(ic->i_cm_id, (union ib_gid *)&iinfo->src_gid,
                               (union ib_gid *)&iinfo->dst_gid);
 
@@ -329,7 +330,7 @@ static int rds6_ib_conn_info_visitor(struct rds_connection *conn,
                                     void *buffer)
 {
        struct rds6_info_rdma_connection *iinfo6 = buffer;
-       struct rds_ib_connection *ic;
+       struct rds_ib_connection *ic = conn->c_transport_data;
 
        /* We will only ever look at IB transports */
        if (conn->c_trans != &rds_ib_transport)
@@ -337,6 +338,10 @@ static int rds6_ib_conn_info_visitor(struct rds_connection *conn,
 
        iinfo6->src_addr = conn->c_laddr;
        iinfo6->dst_addr = conn->c_faddr;
+       if (ic) {
+               iinfo6->tos = conn->c_tos;
+               iinfo6->sl = ic->i_sl;
+       }
 
        memset(&iinfo6->src_gid, 0, sizeof(iinfo6->src_gid));
        memset(&iinfo6->dst_gid, 0, sizeof(iinfo6->dst_gid));
@@ -344,7 +349,6 @@ static int rds6_ib_conn_info_visitor(struct rds_connection *conn,
        if (rds_conn_state(conn) == RDS_CONN_UP) {
                struct rds_ib_device *rds_ibdev;
 
-               ic = conn->c_transport_data;
                rdma_read_gids(ic->i_cm_id, (union ib_gid *)&iinfo6->src_gid,
                               (union ib_gid *)&iinfo6->dst_gid);
                rds_ibdev = ic->rds_ibdev;
index 303c6ee..f2b558e 100644 (file)
@@ -220,6 +220,7 @@ struct rds_ib_connection {
        /* Send/Recv vectors */
        int                     i_scq_vector;
        int                     i_rcq_vector;
+       u8                      i_sl;
 };
 
 /* This assumes that atomic_t is at least 32 bits */
index fddaa09..233f136 100644 (file)
@@ -152,6 +152,9 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
                  RDS_PROTOCOL_MINOR(conn->c_version),
                  ic->i_flowctl ? ", flow control" : "");
 
+       /* receive sl from the peer */
+       ic->i_sl = ic->i_cm_id->route.path_rec->sl;
+
        atomic_set(&ic->i_cq_quiesce, 0);
 
        /* Init rings and fill recv. this needs to wait until protocol
index 9986d60..5f741e5 100644 (file)
@@ -43,6 +43,9 @@ static struct rdma_cm_id *rds_rdma_listen_id;
 static struct rdma_cm_id *rds6_rdma_listen_id;
 #endif
 
+/* Per IB specification 7.7.3, service level is a 4-bit field. */
+#define TOS_TO_SL(tos)         ((tos) & 0xF)
+
 static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
                                         struct rdma_cm_event *event,
                                         bool isv6)
@@ -97,10 +100,13 @@ static int rds_rdma_cm_event_handler_cmn(struct rdma_cm_id *cm_id,
                        struct rds_ib_connection *ibic;
 
                        ibic = conn->c_transport_data;
-                       if (ibic && ibic->i_cm_id == cm_id)
+                       if (ibic && ibic->i_cm_id == cm_id) {
+                               cm_id->route.path_rec[0].sl =
+                                       TOS_TO_SL(conn->c_tos);
                                ret = trans->cm_initiate_connect(cm_id, isv6);
-                       else
+                       } else {
                                rds_conn_drop(conn);
+                       }
                }
                break;
 
index 853de48..a42ba7f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -811,6 +811,7 @@ void rds6_inc_info_copy(struct rds_incoming *inc,
 
        minfo6.seq = be64_to_cpu(inc->i_hdr.h_sequence);
        minfo6.len = be32_to_cpu(inc->i_hdr.h_len);
+       minfo6.tos = inc->i_conn->c_tos;
 
        if (flip) {
                minfo6.laddr = *daddr;
@@ -824,6 +825,8 @@ void rds6_inc_info_copy(struct rds_incoming *inc,
                minfo6.fport = inc->i_hdr.h_dport;
        }
 
+       minfo6.flags = 0;
+
        rds_info_copy(iter, &minfo6, sizeof(minfo6));
 }
 #endif
index d09eaf1..d72ddb6 100644 (file)
@@ -193,7 +193,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 
 service_in_use:
        write_unlock(&local->services_lock);
-       rxrpc_put_local(local);
+       rxrpc_unuse_local(local);
        ret = -EADDRINUSE;
 error_unlock:
        release_sock(&rx->sk);
@@ -402,7 +402,7 @@ EXPORT_SYMBOL(rxrpc_kernel_check_life);
  */
 void rxrpc_kernel_probe_life(struct socket *sock, struct rxrpc_call *call)
 {
-       rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+       rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                          rxrpc_propose_ack_ping_for_check_life);
        rxrpc_send_ack_packet(call, true, NULL);
 }
@@ -862,7 +862,6 @@ static void rxrpc_sock_destructor(struct sock *sk)
 static int rxrpc_release_sock(struct sock *sk)
 {
        struct rxrpc_sock *rx = rxrpc_sk(sk);
-       struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
 
        _enter("%p{%d,%d}", sk, sk->sk_state, refcount_read(&sk->sk_refcnt));
 
@@ -898,10 +897,8 @@ static int rxrpc_release_sock(struct sock *sk)
        rxrpc_release_calls_on_socket(rx);
        flush_workqueue(rxrpc_workqueue);
        rxrpc_purge_queue(&sk->sk_receive_queue);
-       rxrpc_queue_work(&rxnet->service_conn_reaper);
-       rxrpc_queue_work(&rxnet->client_conn_reaper);
 
-       rxrpc_put_local(rx->local);
+       rxrpc_unuse_local(rx->local);
        rx->local = NULL;
        key_put(rx->key);
        rx->key = NULL;
index 822f453..8051dfd 100644 (file)
@@ -185,11 +185,17 @@ struct rxrpc_host_header {
  * - max 48 bytes (struct sk_buff::cb)
  */
 struct rxrpc_skb_priv {
-       union {
-               u8              nr_jumbo;       /* Number of jumbo subpackets */
-       };
+       atomic_t        nr_ring_pins;           /* Number of rxtx ring pins */
+       u8              nr_subpackets;          /* Number of subpackets */
+       u8              rx_flags;               /* Received packet flags */
+#define RXRPC_SKB_INCL_LAST    0x01            /* - Includes last packet */
+#define RXRPC_SKB_TX_BUFFER    0x02            /* - Is transmit buffer */
        union {
                int             remain;         /* amount of space remaining for next write */
+
+               /* List of requested ACKs on subpackets */
+               unsigned long   rx_req_ack[(RXRPC_MAX_NR_JUMBO + BITS_PER_LONG - 1) /
+                                          BITS_PER_LONG];
        };
 
        struct rxrpc_host_header hdr;           /* RxRPC packet header from this packet */
@@ -254,7 +260,8 @@ struct rxrpc_security {
  */
 struct rxrpc_local {
        struct rcu_head         rcu;
-       atomic_t                usage;
+       atomic_t                active_users;   /* Number of users of the local endpoint */
+       atomic_t                usage;          /* Number of references to the structure */
        struct rxrpc_net        *rxnet;         /* The network ns in which this resides */
        struct list_head        link;
        struct socket           *socket;        /* my UDP socket */
@@ -612,8 +619,7 @@ struct rxrpc_call {
 #define RXRPC_TX_ANNO_LAST     0x04
 #define RXRPC_TX_ANNO_RESENT   0x08
 
-#define RXRPC_RX_ANNO_JUMBO    0x3f            /* Jumbo subpacket number + 1 if not zero */
-#define RXRPC_RX_ANNO_JLAST    0x40            /* Set if last element of a jumbo packet */
+#define RXRPC_RX_ANNO_SUBPACKET        0x3f            /* Subpacket number in jumbogram */
 #define RXRPC_RX_ANNO_VERIFIED 0x80            /* Set if verified and decrypted */
        rxrpc_seq_t             tx_hard_ack;    /* Dead slot in buffer; the first transmitted but
                                                 * not hard-ACK'd packet follows this.
@@ -649,7 +655,6 @@ struct rxrpc_call {
 
        /* receive-phase ACK management */
        u8                      ackr_reason;    /* reason to ACK */
-       u16                     ackr_skew;      /* skew on packet being ACK'd */
        rxrpc_serial_t          ackr_serial;    /* serial of packet being ACK'd */
        rxrpc_serial_t          ackr_first_seq; /* first sequence number received */
        rxrpc_seq_t             ackr_prev_seq;  /* previous sequence number received */
@@ -743,7 +748,7 @@ int rxrpc_reject_call(struct rxrpc_sock *);
 /*
  * call_event.c
  */
-void rxrpc_propose_ACK(struct rxrpc_call *, u8, u16, u32, bool, bool,
+void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool, bool,
                       enum rxrpc_propose_ack_trace);
 void rxrpc_process_call(struct work_struct *);
 
@@ -905,6 +910,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *);
 void rxrpc_put_client_conn(struct rxrpc_connection *);
 void rxrpc_discard_expired_client_conns(struct work_struct *);
 void rxrpc_destroy_all_client_connections(struct rxrpc_net *);
+void rxrpc_clean_up_local_conns(struct rxrpc_local *);
 
 /*
  * conn_event.c
@@ -1002,6 +1008,8 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *, const struct sockaddr_rxrpc
 struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *);
 struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *);
 void rxrpc_put_local(struct rxrpc_local *);
+struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *);
+void rxrpc_unuse_local(struct rxrpc_local *);
 void rxrpc_queue_local(struct rxrpc_local *);
 void rxrpc_destroy_all_locals(struct rxrpc_net *);
 
@@ -1103,6 +1111,7 @@ void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
 void rxrpc_packet_destructor(struct sk_buff *);
 void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
 void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
+void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace);
 void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
 void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
 void rxrpc_purge_queue(struct sk_buff_head *);
index bc2adeb..cedbbb3 100644 (file)
@@ -43,8 +43,7 @@ static void rxrpc_propose_ping(struct rxrpc_call *call,
  * propose an ACK be sent
  */
 static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                               u16 skew, u32 serial, bool immediate,
-                               bool background,
+                               u32 serial, bool immediate, bool background,
                                enum rxrpc_propose_ack_trace why)
 {
        enum rxrpc_propose_ack_outcome outcome = rxrpc_propose_ack_use;
@@ -69,14 +68,12 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                if (RXRPC_ACK_UPDATEABLE & (1 << ack_reason)) {
                        outcome = rxrpc_propose_ack_update;
                        call->ackr_serial = serial;
-                       call->ackr_skew = skew;
                }
                if (!immediate)
                        goto trace;
        } else if (prior > rxrpc_ack_priority[call->ackr_reason]) {
                call->ackr_reason = ack_reason;
                call->ackr_serial = serial;
-               call->ackr_skew = skew;
        } else {
                outcome = rxrpc_propose_ack_subsume;
        }
@@ -137,11 +134,11 @@ trace:
  * propose an ACK be sent, locking the call structure
  */
 void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                      u16 skew, u32 serial, bool immediate, bool background,
+                      u32 serial, bool immediate, bool background,
                       enum rxrpc_propose_ack_trace why)
 {
        spin_lock_bh(&call->lock);
-       __rxrpc_propose_ACK(call, ack_reason, skew, serial,
+       __rxrpc_propose_ACK(call, ack_reason, serial,
                            immediate, background, why);
        spin_unlock_bh(&call->lock);
 }
@@ -202,7 +199,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
                        continue;
 
                skb = call->rxtx_buffer[ix];
-               rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
 
                if (anno_type == RXRPC_TX_ANNO_UNACK) {
                        if (ktime_after(skb->tstamp, max_age)) {
@@ -239,7 +236,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
                ack_ts = ktime_sub(now, call->acks_latest_ts);
                if (ktime_to_ns(ack_ts) < call->peer->rtt)
                        goto out;
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                                  rxrpc_propose_ack_ping_for_lost_ack);
                rxrpc_send_ack_packet(call, true, NULL);
                goto out;
@@ -258,18 +255,18 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
                        continue;
 
                skb = call->rxtx_buffer[ix];
-               rxrpc_get_skb(skb, rxrpc_skb_tx_got);
+               rxrpc_get_skb(skb, rxrpc_skb_got);
                spin_unlock_bh(&call->lock);
 
                if (rxrpc_send_data_packet(call, skb, true) < 0) {
-                       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        return;
                }
 
                if (rxrpc_is_client_call(call))
                        rxrpc_expose_client_call(call);
 
-               rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                spin_lock_bh(&call->lock);
 
                /* We need to clear the retransmit state, but there are two
@@ -372,7 +369,7 @@ recheck_state:
        if (time_after_eq(now, t)) {
                trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now);
                cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET);
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, true,
                                  rxrpc_propose_ack_ping_for_keepalive);
                set_bit(RXRPC_CALL_EV_PING, &call->events);
        }
@@ -407,7 +404,7 @@ recheck_state:
        send_ack = NULL;
        if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) {
                call->acks_lost_top = call->tx_top;
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
                                  rxrpc_propose_ack_ping_for_lost_ack);
                send_ack = &call->acks_lost_ping;
        }
index 217b12b..014548c 100644 (file)
@@ -421,6 +421,19 @@ void rxrpc_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
        trace_rxrpc_call(call, op, n, here, NULL);
 }
 
+/*
+ * Clean up the RxTx skb ring.
+ */
+static void rxrpc_cleanup_ring(struct rxrpc_call *call)
+{
+       int i;
+
+       for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
+               rxrpc_free_skb(call->rxtx_buffer[i], rxrpc_skb_cleaned);
+               call->rxtx_buffer[i] = NULL;
+       }
+}
+
 /*
  * Detach a call from its owning socket.
  */
@@ -429,7 +442,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
        const void *here = __builtin_return_address(0);
        struct rxrpc_connection *conn = call->conn;
        bool put = false;
-       int i;
 
        _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage));
 
@@ -479,13 +491,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
        if (conn)
                rxrpc_disconnect_call(call);
 
-       for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
-               rxrpc_free_skb(call->rxtx_buffer[i],
-                              (call->tx_phase ? rxrpc_skb_tx_cleaned :
-                               rxrpc_skb_rx_cleaned));
-               call->rxtx_buffer[i] = NULL;
-       }
-
+       rxrpc_cleanup_ring(call);
        _leave("");
 }
 
@@ -568,8 +574,6 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu)
  */
 void rxrpc_cleanup_call(struct rxrpc_call *call)
 {
-       int i;
-
        _net("DESTROY CALL %d", call->debug_id);
 
        memset(&call->sock_node, 0xcd, sizeof(call->sock_node));
@@ -580,13 +584,8 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
        ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
        ASSERTCMP(call->conn, ==, NULL);
 
-       /* Clean up the Rx/Tx buffer */
-       for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++)
-               rxrpc_free_skb(call->rxtx_buffer[i],
-                              (call->tx_phase ? rxrpc_skb_tx_cleaned :
-                               rxrpc_skb_rx_cleaned));
-
-       rxrpc_free_skb(call->tx_pending, rxrpc_skb_tx_cleaned);
+       rxrpc_cleanup_ring(call);
+       rxrpc_free_skb(call->tx_pending, rxrpc_skb_cleaned);
 
        call_rcu(&call->rcu, rxrpc_rcu_destroy_call);
 }
index aea82f9..3f1da1b 100644 (file)
@@ -1162,3 +1162,47 @@ void rxrpc_destroy_all_client_connections(struct rxrpc_net *rxnet)
 
        _leave("");
 }
+
+/*
+ * Clean up the client connections on a local endpoint.
+ */
+void rxrpc_clean_up_local_conns(struct rxrpc_local *local)
+{
+       struct rxrpc_connection *conn, *tmp;
+       struct rxrpc_net *rxnet = local->rxnet;
+       unsigned int nr_active;
+       LIST_HEAD(graveyard);
+
+       _enter("");
+
+       spin_lock(&rxnet->client_conn_cache_lock);
+       nr_active = rxnet->nr_active_client_conns;
+
+       list_for_each_entry_safe(conn, tmp, &rxnet->idle_client_conns,
+                                cache_link) {
+               if (conn->params.local == local) {
+                       ASSERTCMP(conn->cache_state, ==, RXRPC_CONN_CLIENT_IDLE);
+
+                       trace_rxrpc_client(conn, -1, rxrpc_client_discard);
+                       if (!test_and_clear_bit(RXRPC_CONN_EXPOSED, &conn->flags))
+                               BUG();
+                       conn->cache_state = RXRPC_CONN_CLIENT_INACTIVE;
+                       list_move(&conn->cache_link, &graveyard);
+                       nr_active--;
+               }
+       }
+
+       rxnet->nr_active_client_conns = nr_active;
+       spin_unlock(&rxnet->client_conn_cache_lock);
+       ASSERTCMP(nr_active, >=, 0);
+
+       while (!list_empty(&graveyard)) {
+               conn = list_entry(graveyard.next,
+                                 struct rxrpc_connection, cache_link);
+               list_del_init(&conn->cache_link);
+
+               rxrpc_put_connection(conn);
+       }
+
+       _leave(" [culled]");
+}
index df6624c..a1ceef4 100644 (file)
@@ -472,7 +472,7 @@ void rxrpc_process_connection(struct work_struct *work)
        /* go through the conn-level event packets, releasing the ref on this
         * connection that each one has when we've finished with it */
        while ((skb = skb_dequeue(&conn->rx_queue))) {
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                ret = rxrpc_process_event(conn, skb, &abort_code);
                switch (ret) {
                case -EPROTO:
@@ -484,7 +484,7 @@ void rxrpc_process_connection(struct work_struct *work)
                        goto requeue_and_leave;
                case -ECONNABORTED:
                default:
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        break;
                }
        }
@@ -501,6 +501,6 @@ requeue_and_leave:
 protocol_error:
        if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
                goto requeue_and_leave;
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        goto out;
 }
index 434ef39..ed05b69 100644 (file)
@@ -398,7 +398,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work)
                if (conn->state == RXRPC_CONN_SERVICE_PREALLOC)
                        continue;
 
-               if (rxnet->live) {
+               if (rxnet->live && !conn->params.local->dead) {
                        idle_timestamp = READ_ONCE(conn->idle_timestamp);
                        expire_at = idle_timestamp + rxrpc_connection_expiry * HZ;
                        if (conn->params.local->service_closed)
index 5bd6f15..157be1f 100644 (file)
@@ -196,15 +196,14 @@ send_extra_data:
  * Ping the other end to fill our RTT cache and to retrieve the rwind
  * and MTU parameters.
  */
-static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb,
-                           int skew)
+static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        ktime_t now = skb->tstamp;
 
        if (call->peer->rtt_usage < 3 ||
            ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, skew, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
                                  true, true,
                                  rxrpc_propose_ack_ping_for_params);
 }
@@ -234,7 +233,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
                ix = call->tx_hard_ack & RXRPC_RXTX_BUFF_MASK;
                skb = call->rxtx_buffer[ix];
                annotation = call->rxtx_annotations[ix];
-               rxrpc_see_skb(skb, rxrpc_skb_tx_rotated);
+               rxrpc_see_skb(skb, rxrpc_skb_rotated);
                call->rxtx_buffer[ix] = NULL;
                call->rxtx_annotations[ix] = 0;
                skb->next = list;
@@ -259,7 +258,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
                skb = list;
                list = skb->next;
                skb_mark_not_on_list(skb);
-               rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        return rot_last;
@@ -348,7 +347,7 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call)
 }
 
 /*
- * Scan a jumbo packet to validate its structure and to work out how many
+ * Scan a data packet to validate its structure and to work out how many
  * subpackets it contains.
  *
  * A jumbo packet is a collection of consecutive packets glued together with
@@ -359,16 +358,21 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call)
  * the last are RXRPC_JUMBO_DATALEN in size.  The last subpacket may be of any
  * size.
  */
-static bool rxrpc_validate_jumbo(struct sk_buff *skb)
+static bool rxrpc_validate_data(struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        unsigned int offset = sizeof(struct rxrpc_wire_header);
        unsigned int len = skb->len;
-       int nr_jumbo = 1;
        u8 flags = sp->hdr.flags;
 
-       do {
-               nr_jumbo++;
+       for (;;) {
+               if (flags & RXRPC_REQUEST_ACK)
+                       __set_bit(sp->nr_subpackets, sp->rx_req_ack);
+               sp->nr_subpackets++;
+
+               if (!(flags & RXRPC_JUMBO_PACKET))
+                       break;
+
                if (len - offset < RXRPC_JUMBO_SUBPKTLEN)
                        goto protocol_error;
                if (flags & RXRPC_LAST_PACKET)
@@ -377,9 +381,10 @@ static bool rxrpc_validate_jumbo(struct sk_buff *skb)
                if (skb_copy_bits(skb, offset, &flags, 1) < 0)
                        goto protocol_error;
                offset += sizeof(struct rxrpc_jumbo_header);
-       } while (flags & RXRPC_JUMBO_PACKET);
+       }
 
-       sp->nr_jumbo = nr_jumbo;
+       if (flags & RXRPC_LAST_PACKET)
+               sp->rx_flags |= RXRPC_SKB_INCL_LAST;
        return true;
 
 protocol_error:
@@ -400,10 +405,10 @@ protocol_error:
  * (that information is encoded in the ACK packet).
  */
 static void rxrpc_input_dup_data(struct rxrpc_call *call, rxrpc_seq_t seq,
-                                u8 annotation, bool *_jumbo_bad)
+                                bool is_jumbo, bool *_jumbo_bad)
 {
        /* Discard normal packets that are duplicates. */
-       if (annotation == 0)
+       if (is_jumbo)
                return;
 
        /* Skip jumbo subpackets that are duplicates.  When we've had three or
@@ -417,30 +422,30 @@ static void rxrpc_input_dup_data(struct rxrpc_call *call, rxrpc_seq_t seq,
 }
 
 /*
- * Process a DATA packet, adding the packet to the Rx ring.
+ * Process a DATA packet, adding the packet to the Rx ring.  The caller's
+ * packet ref must be passed on or discarded.
  */
-static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
-                            u16 skew)
+static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        enum rxrpc_call_state state;
-       unsigned int offset = sizeof(struct rxrpc_wire_header);
-       unsigned int ix;
+       unsigned int j;
        rxrpc_serial_t serial = sp->hdr.serial, ack_serial = 0;
-       rxrpc_seq_t seq = sp->hdr.seq, hard_ack;
-       bool immediate_ack = false, jumbo_bad = false, queued;
-       u16 len;
-       u8 ack = 0, flags, annotation = 0;
+       rxrpc_seq_t seq0 = sp->hdr.seq, hard_ack;
+       bool immediate_ack = false, jumbo_bad = false;
+       u8 ack = 0;
 
        _enter("{%u,%u},{%u,%u}",
-              call->rx_hard_ack, call->rx_top, skb->len, seq);
+              call->rx_hard_ack, call->rx_top, skb->len, seq0);
 
-       _proto("Rx DATA %%%u { #%u f=%02x }",
-              sp->hdr.serial, seq, sp->hdr.flags);
+       _proto("Rx DATA %%%u { #%u f=%02x n=%u }",
+              sp->hdr.serial, seq0, sp->hdr.flags, sp->nr_subpackets);
 
        state = READ_ONCE(call->state);
-       if (state >= RXRPC_CALL_COMPLETE)
+       if (state >= RXRPC_CALL_COMPLETE) {
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                return;
+       }
 
        if (call->state == RXRPC_CALL_SERVER_RECV_REQUEST) {
                unsigned long timo = READ_ONCE(call->next_req_timo);
@@ -465,156 +470,157 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,
            !rxrpc_receiving_reply(call))
                goto unlock;
 
-       call->ackr_prev_seq = seq;
-
+       call->ackr_prev_seq = seq0;
        hard_ack = READ_ONCE(call->rx_hard_ack);
-       if (after(seq, hard_ack + call->rx_winsize)) {
-               ack = RXRPC_ACK_EXCEEDS_WINDOW;
-               ack_serial = serial;
-               goto ack;
-       }
 
-       flags = sp->hdr.flags;
-       if (flags & RXRPC_JUMBO_PACKET) {
+       if (sp->nr_subpackets > 1) {
                if (call->nr_jumbo_bad > 3) {
                        ack = RXRPC_ACK_NOSPACE;
                        ack_serial = serial;
                        goto ack;
                }
-               annotation = 1;
        }
 
-next_subpacket:
-       queued = false;
-       ix = seq & RXRPC_RXTX_BUFF_MASK;
-       len = skb->len;
-       if (flags & RXRPC_JUMBO_PACKET)
-               len = RXRPC_JUMBO_DATALEN;
-
-       if (flags & RXRPC_LAST_PACKET) {
-               if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
-                   seq != call->rx_top) {
-                       rxrpc_proto_abort("LSN", call, seq);
-                       goto unlock;
-               }
-       } else {
-               if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
-                   after_eq(seq, call->rx_top)) {
-                       rxrpc_proto_abort("LSA", call, seq);
-                       goto unlock;
+       for (j = 0; j < sp->nr_subpackets; j++) {
+               rxrpc_serial_t serial = sp->hdr.serial + j;
+               rxrpc_seq_t seq = seq0 + j;
+               unsigned int ix = seq & RXRPC_RXTX_BUFF_MASK;
+               bool terminal = (j == sp->nr_subpackets - 1);
+               bool last = terminal && (sp->rx_flags & RXRPC_SKB_INCL_LAST);
+               u8 flags, annotation = j;
+
+               _proto("Rx DATA+%u %%%u { #%x t=%u l=%u }",
+                    j, serial, seq, terminal, last);
+
+               if (last) {
+                       if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
+                           seq != call->rx_top) {
+                               rxrpc_proto_abort("LSN", call, seq);
+                               goto unlock;
+                       }
+               } else {
+                       if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
+                           after_eq(seq, call->rx_top)) {
+                               rxrpc_proto_abort("LSA", call, seq);
+                               goto unlock;
+                       }
                }
-       }
-
-       trace_rxrpc_rx_data(call->debug_id, seq, serial, flags, annotation);
-       if (before_eq(seq, hard_ack)) {
-               ack = RXRPC_ACK_DUPLICATE;
-               ack_serial = serial;
-               goto skip;
-       }
 
-       if (flags & RXRPC_REQUEST_ACK && !ack) {
-               ack = RXRPC_ACK_REQUESTED;
-               ack_serial = serial;
-       }
+               flags = 0;
+               if (last)
+                       flags |= RXRPC_LAST_PACKET;
+               if (!terminal)
+                       flags |= RXRPC_JUMBO_PACKET;
+               if (test_bit(j, sp->rx_req_ack))
+                       flags |= RXRPC_REQUEST_ACK;
+               trace_rxrpc_rx_data(call->debug_id, seq, serial, flags, annotation);
 
-       if (call->rxtx_buffer[ix]) {
-               rxrpc_input_dup_data(call, seq, annotation, &jumbo_bad);
-               if (ack != RXRPC_ACK_DUPLICATE) {
+               if (before_eq(seq, hard_ack)) {
                        ack = RXRPC_ACK_DUPLICATE;
                        ack_serial = serial;
+                       continue;
                }
-               immediate_ack = true;
-               goto skip;
-       }
-
-       /* Queue the packet.  We use a couple of memory barriers here as need
-        * to make sure that rx_top is perceived to be set after the buffer
-        * pointer and that the buffer pointer is set after the annotation and
-        * the skb data.
-        *
-        * Barriers against rxrpc_recvmsg_data() and rxrpc_rotate_rx_window()
-        * and also rxrpc_fill_out_ack().
-        */
-       rxrpc_get_skb(skb, rxrpc_skb_rx_got);
-       call->rxtx_annotations[ix] = annotation;
-       smp_wmb();
-       call->rxtx_buffer[ix] = skb;
-       if (after(seq, call->rx_top)) {
-               smp_store_release(&call->rx_top, seq);
-       } else if (before(seq, call->rx_top)) {
-               /* Send an immediate ACK if we fill in a hole */
-               if (!ack) {
-                       ack = RXRPC_ACK_DELAY;
-                       ack_serial = serial;
-               }
-               immediate_ack = true;
-       }
-       if (flags & RXRPC_LAST_PACKET) {
-               set_bit(RXRPC_CALL_RX_LAST, &call->flags);
-               trace_rxrpc_receive(call, rxrpc_receive_queue_last, serial, seq);
-       } else {
-               trace_rxrpc_receive(call, rxrpc_receive_queue, serial, seq);
-       }
-       queued = true;
 
-       if (after_eq(seq, call->rx_expect_next)) {
-               if (after(seq, call->rx_expect_next)) {
-                       _net("OOS %u > %u", seq, call->rx_expect_next);
-                       ack = RXRPC_ACK_OUT_OF_SEQUENCE;
-                       ack_serial = serial;
+               if (call->rxtx_buffer[ix]) {
+                       rxrpc_input_dup_data(call, seq, sp->nr_subpackets > 1,
+                                            &jumbo_bad);
+                       if (ack != RXRPC_ACK_DUPLICATE) {
+                               ack = RXRPC_ACK_DUPLICATE;
+                               ack_serial = serial;
+                       }
+                       immediate_ack = true;
+                       continue;
                }
-               call->rx_expect_next = seq + 1;
-       }
 
-skip:
-       offset += len;
-       if (flags & RXRPC_JUMBO_PACKET) {
-               if (skb_copy_bits(skb, offset, &flags, 1) < 0) {
-                       rxrpc_proto_abort("XJF", call, seq);
-                       goto unlock;
-               }
-               offset += sizeof(struct rxrpc_jumbo_header);
-               seq++;
-               serial++;
-               annotation++;
-               if (flags & RXRPC_JUMBO_PACKET)
-                       annotation |= RXRPC_RX_ANNO_JLAST;
                if (after(seq, hard_ack + call->rx_winsize)) {
                        ack = RXRPC_ACK_EXCEEDS_WINDOW;
                        ack_serial = serial;
-                       if (!jumbo_bad) {
-                               call->nr_jumbo_bad++;
-                               jumbo_bad = true;
+                       if (flags & RXRPC_JUMBO_PACKET) {
+                               if (!jumbo_bad) {
+                                       call->nr_jumbo_bad++;
+                                       jumbo_bad = true;
+                               }
                        }
+
                        goto ack;
                }
 
-               _proto("Rx DATA Jumbo %%%u", serial);
-               goto next_subpacket;
-       }
+               if (flags & RXRPC_REQUEST_ACK && !ack) {
+                       ack = RXRPC_ACK_REQUESTED;
+                       ack_serial = serial;
+               }
+
+               /* Queue the packet.  We use a couple of memory barriers here as need
+                * to make sure that rx_top is perceived to be set after the buffer
+                * pointer and that the buffer pointer is set after the annotation and
+                * the skb data.
+                *
+                * Barriers against rxrpc_recvmsg_data() and rxrpc_rotate_rx_window()
+                * and also rxrpc_fill_out_ack().
+                */
+               if (!terminal)
+                       rxrpc_get_skb(skb, rxrpc_skb_got);
+               call->rxtx_annotations[ix] = annotation;
+               smp_wmb();
+               call->rxtx_buffer[ix] = skb;
+               if (after(seq, call->rx_top)) {
+                       smp_store_release(&call->rx_top, seq);
+               } else if (before(seq, call->rx_top)) {
+                       /* Send an immediate ACK if we fill in a hole */
+                       if (!ack) {
+                               ack = RXRPC_ACK_DELAY;
+                               ack_serial = serial;
+                       }
+                       immediate_ack = true;
+               }
 
-       if (queued && flags & RXRPC_LAST_PACKET && !ack) {
-               ack = RXRPC_ACK_DELAY;
-               ack_serial = serial;
+               if (terminal) {
+                       /* From this point on, we're not allowed to touch the
+                        * packet any longer as its ref now belongs to the Rx
+                        * ring.
+                        */
+                       skb = NULL;
+               }
+
+               if (last) {
+                       set_bit(RXRPC_CALL_RX_LAST, &call->flags);
+                       if (!ack) {
+                               ack = RXRPC_ACK_DELAY;
+                               ack_serial = serial;
+                       }
+                       trace_rxrpc_receive(call, rxrpc_receive_queue_last, serial, seq);
+               } else {
+                       trace_rxrpc_receive(call, rxrpc_receive_queue, serial, seq);
+               }
+
+               if (after_eq(seq, call->rx_expect_next)) {
+                       if (after(seq, call->rx_expect_next)) {
+                               _net("OOS %u > %u", seq, call->rx_expect_next);
+                               ack = RXRPC_ACK_OUT_OF_SEQUENCE;
+                               ack_serial = serial;
+                       }
+                       call->rx_expect_next = seq + 1;
+               }
        }
 
 ack:
        if (ack)
-               rxrpc_propose_ACK(call, ack, skew, ack_serial,
+               rxrpc_propose_ACK(call, ack, ack_serial,
                                  immediate_ack, true,
                                  rxrpc_propose_ack_input_data);
        else
-               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, skew, serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
                                  false, true,
                                  rxrpc_propose_ack_input_data);
 
-       if (sp->hdr.seq == READ_ONCE(call->rx_hard_ack) + 1) {
+       if (seq0 == READ_ONCE(call->rx_hard_ack) + 1) {
                trace_rxrpc_notify_socket(call->debug_id, serial);
                rxrpc_notify_socket(call);
        }
 
 unlock:
        spin_unlock(&call->input_lock);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" [queued]");
 }
 
@@ -822,8 +828,7 @@ static void rxrpc_input_soft_acks(struct rxrpc_call *call, u8 *acks,
  * soft-ACK means that the packet may be discarded and retransmission
  * requested.  A phase is complete when all packets are hard-ACK'd.
  */
-static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
-                           u16 skew)
+static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_ack_summary summary = { 0 };
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
@@ -867,11 +872,11 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
        if (buf.ack.reason == RXRPC_ACK_PING) {
                _proto("Rx ACK %%%u PING Request", sp->hdr.serial);
                rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
-                                 skew, sp->hdr.serial, true, true,
+                                 sp->hdr.serial, true, true,
                                  rxrpc_propose_ack_respond_to_ping);
        } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED,
-                                 skew, sp->hdr.serial, true, true,
+                                 sp->hdr.serial, true, true,
                                  rxrpc_propose_ack_respond_to_ack);
        }
 
@@ -948,7 +953,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
            RXRPC_TX_ANNO_LAST &&
            summary.nr_acks == call->tx_top - hard_ack &&
            rxrpc_is_client_call(call))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, skew, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
                                  false, true,
                                  rxrpc_propose_ack_ping_for_lost_reply);
 
@@ -1004,7 +1009,7 @@ static void rxrpc_input_abort(struct rxrpc_call *call, struct sk_buff *skb)
  * Process an incoming call packet.
  */
 static void rxrpc_input_call_packet(struct rxrpc_call *call,
-                                   struct sk_buff *skb, u16 skew)
+                                   struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        unsigned long timo;
@@ -1023,11 +1028,11 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,
 
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_DATA:
-               rxrpc_input_data(call, skb, skew);
-               break;
+               rxrpc_input_data(call, skb);
+               goto no_free;
 
        case RXRPC_PACKET_TYPE_ACK:
-               rxrpc_input_ack(call, skb, skew);
+               rxrpc_input_ack(call, skb);
                break;
 
        case RXRPC_PACKET_TYPE_BUSY:
@@ -1051,6 +1056,8 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,
                break;
        }
 
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
+no_free:
        _leave("");
 }
 
@@ -1108,8 +1115,12 @@ static void rxrpc_post_packet_to_local(struct rxrpc_local *local,
 {
        _enter("%p,%p", local, skb);
 
-       skb_queue_tail(&local->event_queue, skb);
-       rxrpc_queue_local(local);
+       if (rxrpc_get_local_maybe(local)) {
+               skb_queue_tail(&local->event_queue, skb);
+               rxrpc_queue_local(local);
+       } else {
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
+       }
 }
 
 /*
@@ -1119,8 +1130,12 @@ static void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
 {
        CHECK_SLAB_OKAY(&local->usage);
 
-       skb_queue_tail(&local->reject_queue, skb);
-       rxrpc_queue_local(local);
+       if (rxrpc_get_local_maybe(local)) {
+               skb_queue_tail(&local->reject_queue, skb);
+               rxrpc_queue_local(local);
+       } else {
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
+       }
 }
 
 /*
@@ -1173,7 +1188,6 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
        struct rxrpc_peer *peer = NULL;
        struct rxrpc_sock *rx = NULL;
        unsigned int channel;
-       int skew = 0;
 
        _enter("%p", udp_sk);
 
@@ -1184,7 +1198,7 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
        if (skb->tstamp == 0)
                skb->tstamp = ktime_get_real();
 
-       rxrpc_new_skb(skb, rxrpc_skb_rx_received);
+       rxrpc_new_skb(skb, rxrpc_skb_received);
 
        skb_pull(skb, sizeof(struct udphdr));
 
@@ -1201,7 +1215,7 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                static int lose;
                if ((lose++ & 7) == 7) {
                        trace_rxrpc_rx_lose(sp);
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_lost);
+                       rxrpc_free_skb(skb, rxrpc_skb_lost);
                        return 0;
                }
        }
@@ -1233,9 +1247,26 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                if (sp->hdr.callNumber == 0 ||
                    sp->hdr.seq == 0)
                        goto bad_message;
-               if (sp->hdr.flags & RXRPC_JUMBO_PACKET &&
-                   !rxrpc_validate_jumbo(skb))
+               if (!rxrpc_validate_data(skb))
                        goto bad_message;
+
+               /* Unshare the packet so that it can be modified for in-place
+                * decryption.
+                */
+               if (sp->hdr.securityIndex != 0) {
+                       struct sk_buff *nskb = skb_unshare(skb, GFP_ATOMIC);
+                       if (!nskb) {
+                               rxrpc_eaten_skb(skb, rxrpc_skb_unshared_nomem);
+                               goto out;
+                       }
+
+                       if (nskb != skb) {
+                               rxrpc_eaten_skb(skb, rxrpc_skb_received);
+                               skb = nskb;
+                               rxrpc_new_skb(skb, rxrpc_skb_unshared);
+                               sp = rxrpc_skb(skb);
+                       }
+               }
                break;
 
        case RXRPC_PACKET_TYPE_CHALLENGE:
@@ -1301,15 +1332,8 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                        goto out;
                }
 
-               /* Note the serial number skew here */
-               skew = (int)sp->hdr.serial - (int)conn->hi_serial;
-               if (skew >= 0) {
-                       if (skew > 0)
-                               conn->hi_serial = sp->hdr.serial;
-               } else {
-                       skew = -skew;
-                       skew = min(skew, 65535);
-               }
+               if ((int)sp->hdr.serial - (int)conn->hi_serial > 0)
+                       conn->hi_serial = sp->hdr.serial;
 
                /* Call-bound packets are routed by connection channel. */
                channel = sp->hdr.cid & RXRPC_CHANNELMASK;
@@ -1372,15 +1396,18 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb)
                call = rxrpc_new_incoming_call(local, rx, skb);
                if (!call)
                        goto reject_packet;
-               rxrpc_send_ping(call, skb, skew);
+               rxrpc_send_ping(call, skb);
                mutex_unlock(&call->user_mutex);
        }
 
-       rxrpc_input_call_packet(call, skb, skew);
-       goto discard;
+       /* Process a call packet; this either discards or passes on the ref
+        * elsewhere.
+        */
+       rxrpc_input_call_packet(call, skb);
+       goto out;
 
 discard:
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
 out:
        trace_rxrpc_rx_done(0, 0);
        return 0;
index e93a78f..3ce6d62 100644 (file)
@@ -90,7 +90,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
        if (skb) {
                struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
 
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
 
                switch (sp->hdr.type) {
@@ -108,7 +108,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
                        break;
                }
 
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        _leave("");
index b1c71ba..3658726 100644 (file)
@@ -79,6 +79,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
        local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
        if (local) {
                atomic_set(&local->usage, 1);
+               atomic_set(&local->active_users, 1);
                local->rxnet = rxnet;
                INIT_LIST_HEAD(&local->link);
                INIT_WORK(&local->processor, rxrpc_local_processor);
@@ -92,7 +93,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
                local->debug_id = atomic_inc_return(&rxrpc_debug_id);
                memcpy(&local->srx, srx, sizeof(*srx));
                local->srx.srx_service = 0;
-               trace_rxrpc_local(local, rxrpc_local_new, 1, NULL);
+               trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, NULL);
        }
 
        _leave(" = %p", local);
@@ -266,11 +267,8 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
                 * bind the transport socket may still fail if we're attempting
                 * to use a local address that the dying object is still using.
                 */
-               if (!rxrpc_get_local_maybe(local)) {
-                       cursor = cursor->next;
-                       list_del_init(&local->link);
+               if (!rxrpc_use_local(local))
                        break;
-               }
 
                age = "old";
                goto found;
@@ -284,7 +282,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
        if (ret < 0)
                goto sock_error;
 
-       list_add_tail(&local->link, cursor);
+       if (cursor != &rxnet->local_endpoints)
+               list_replace_init(cursor, &local->link);
+       else
+               list_add_tail(&local->link, cursor);
        age = "new";
 
 found:
@@ -320,7 +321,7 @@ struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local)
        int n;
 
        n = atomic_inc_return(&local->usage);
-       trace_rxrpc_local(local, rxrpc_local_got, n, here);
+       trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here);
        return local;
 }
 
@@ -334,7 +335,8 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
        if (local) {
                int n = atomic_fetch_add_unless(&local->usage, 1, 0);
                if (n > 0)
-                       trace_rxrpc_local(local, rxrpc_local_got, n + 1, here);
+                       trace_rxrpc_local(local->debug_id, rxrpc_local_got,
+                                         n + 1, here);
                else
                        local = NULL;
        }
@@ -342,24 +344,18 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
 }
 
 /*
- * Queue a local endpoint.
+ * Queue a local endpoint and pass the caller's reference to the work item.
  */
 void rxrpc_queue_local(struct rxrpc_local *local)
 {
        const void *here = __builtin_return_address(0);
+       unsigned int debug_id = local->debug_id;
+       int n = atomic_read(&local->usage);
 
        if (rxrpc_queue_work(&local->processor))
-               trace_rxrpc_local(local, rxrpc_local_queued,
-                                 atomic_read(&local->usage), here);
-}
-
-/*
- * A local endpoint reached its end of life.
- */
-static void __rxrpc_put_local(struct rxrpc_local *local)
-{
-       _enter("%d", local->debug_id);
-       rxrpc_queue_work(&local->processor);
+               trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here);
+       else
+               rxrpc_put_local(local);
 }
 
 /*
@@ -372,10 +368,47 @@ void rxrpc_put_local(struct rxrpc_local *local)
 
        if (local) {
                n = atomic_dec_return(&local->usage);
-               trace_rxrpc_local(local, rxrpc_local_put, n, here);
+               trace_rxrpc_local(local->debug_id, rxrpc_local_put, n, here);
 
                if (n == 0)
-                       __rxrpc_put_local(local);
+                       call_rcu(&local->rcu, rxrpc_local_rcu);
+       }
+}
+
+/*
+ * Start using a local endpoint.
+ */
+struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *local)
+{
+       unsigned int au;
+
+       local = rxrpc_get_local_maybe(local);
+       if (!local)
+               return NULL;
+
+       au = atomic_fetch_add_unless(&local->active_users, 1, 0);
+       if (au == 0) {
+               rxrpc_put_local(local);
+               return NULL;
+       }
+
+       return local;
+}
+
+/*
+ * Cease using a local endpoint.  Once the number of active users reaches 0, we
+ * start the closure of the transport in the work processor.
+ */
+void rxrpc_unuse_local(struct rxrpc_local *local)
+{
+       unsigned int au;
+
+       if (local) {
+               au = atomic_dec_return(&local->active_users);
+               if (au == 0)
+                       rxrpc_queue_local(local);
+               else
+                       rxrpc_put_local(local);
        }
 }
 
@@ -393,21 +426,14 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
 
        _enter("%d", local->debug_id);
 
-       /* We can get a race between an incoming call packet queueing the
-        * processor again and the work processor starting the destruction
-        * process which will shut down the UDP socket.
-        */
-       if (local->dead) {
-               _leave(" [already dead]");
-               return;
-       }
        local->dead = true;
 
        mutex_lock(&rxnet->local_mutex);
        list_del_init(&local->link);
        mutex_unlock(&rxnet->local_mutex);
 
-       ASSERT(RB_EMPTY_ROOT(&local->client_conns));
+       rxrpc_clean_up_local_conns(local);
+       rxrpc_service_connection_reaper(&rxnet->service_conn_reaper);
        ASSERT(!local->service);
 
        if (socket) {
@@ -422,13 +448,11 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
         */
        rxrpc_purge_queue(&local->reject_queue);
        rxrpc_purge_queue(&local->event_queue);
-
-       _debug("rcu local %d", local->debug_id);
-       call_rcu(&local->rcu, rxrpc_local_rcu);
 }
 
 /*
- * Process events on an endpoint
+ * Process events on an endpoint.  The work item carries a ref which
+ * we must release.
  */
 static void rxrpc_local_processor(struct work_struct *work)
 {
@@ -436,13 +460,15 @@ static void rxrpc_local_processor(struct work_struct *work)
                container_of(work, struct rxrpc_local, processor);
        bool again;
 
-       trace_rxrpc_local(local, rxrpc_local_processing,
+       trace_rxrpc_local(local->debug_id, rxrpc_local_processing,
                          atomic_read(&local->usage), NULL);
 
        do {
                again = false;
-               if (atomic_read(&local->usage) == 0)
-                       return rxrpc_local_destroyer(local);
+               if (atomic_read(&local->active_users) == 0) {
+                       rxrpc_local_destroyer(local);
+                       break;
+               }
 
                if (!skb_queue_empty(&local->reject_queue)) {
                        rxrpc_reject_packets(local);
@@ -454,6 +480,8 @@ static void rxrpc_local_processor(struct work_struct *work)
                        again = true;
                }
        } while (again);
+
+       rxrpc_put_local(local);
 }
 
 /*
index 948e3fe..935bb60 100644 (file)
@@ -87,7 +87,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
        *_top = top;
 
        pkt->ack.bufferSpace    = htons(8);
-       pkt->ack.maxSkew        = htons(call->ackr_skew);
+       pkt->ack.maxSkew        = htons(0);
        pkt->ack.firstPacket    = htonl(hard_ack + 1);
        pkt->ack.previousPacket = htonl(call->ackr_prev_seq);
        pkt->ack.serial         = htonl(serial);
@@ -228,7 +228,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
                        if (ping)
                                clear_bit(RXRPC_CALL_PINGING, &call->flags);
                        rxrpc_propose_ACK(call, pkt->ack.reason,
-                                         ntohs(pkt->ack.maxSkew),
                                          ntohl(pkt->ack.serial),
                                          false, true,
                                          rxrpc_propose_ack_retry_tx);
@@ -566,7 +565,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
        memset(&whdr, 0, sizeof(whdr));
 
        while ((skb = skb_dequeue(&local->reject_queue))) {
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                sp = rxrpc_skb(skb);
 
                switch (skb->mark) {
@@ -582,7 +581,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
                        ioc = 2;
                        break;
                default:
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        continue;
                }
 
@@ -607,7 +606,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
                                                      rxrpc_tx_point_reject);
                }
 
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        _leave("");
index 7666ec7..c97ebdc 100644 (file)
@@ -163,11 +163,11 @@ void rxrpc_error_report(struct sock *sk)
                _leave("UDP socket errqueue empty");
                return;
        }
-       rxrpc_new_skb(skb, rxrpc_skb_rx_received);
+       rxrpc_new_skb(skb, rxrpc_skb_received);
        serr = SKB_EXT_ERR(skb);
        if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
                _leave("UDP empty message");
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                return;
        }
 
@@ -177,7 +177,7 @@ void rxrpc_error_report(struct sock *sk)
                peer = NULL;
        if (!peer) {
                rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                _leave(" [no peer]");
                return;
        }
@@ -189,7 +189,7 @@ void rxrpc_error_report(struct sock *sk)
             serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
                rxrpc_adjust_mtu(peer, serr);
                rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                rxrpc_put_peer(peer);
                _leave(" [MTU update]");
                return;
@@ -197,7 +197,7 @@ void rxrpc_error_report(struct sock *sk)
 
        rxrpc_store_error(peer, serr);
        rcu_read_unlock();
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        rxrpc_put_peer(peer);
 
        _leave("");
index 99ce322..49bb972 100644 (file)
@@ -89,6 +89,15 @@ struct rxrpc_jumbo_header {
 #define RXRPC_JUMBO_DATALEN    1412    /* non-terminal jumbo packet data length */
 #define RXRPC_JUMBO_SUBPKTLEN  (RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header))
 
+/*
+ * The maximum number of subpackets that can possibly fit in a UDP packet is:
+ *
+ *     ((max_IP - IP_hdr - UDP_hdr) / RXRPC_JUMBO_SUBPKTLEN) + 1
+ *     = ((65535 - 28 - 28) / 1416) + 1
+ *     = 46 non-terminal packets and 1 terminal packet.
+ */
+#define RXRPC_MAX_NR_JUMBO     47
+
 /*****************************************************************************/
 /*
  * on-the-wire Rx ACK packet data payload
index 5abf46c..3b0becb 100644 (file)
@@ -141,7 +141,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
        ASSERTCMP(call->rx_hard_ack, ==, call->rx_top);
 
        if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) {
-               rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, serial, false, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, false, true,
                                  rxrpc_propose_ack_terminal_ack);
                //rxrpc_send_ack_packet(call, false, NULL);
        }
@@ -159,7 +159,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
                call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
                call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
                write_unlock_bh(&call->state_lock);
-               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial, false, true,
+               rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, false, true,
                                  rxrpc_propose_ack_processing_op);
                break;
        default:
@@ -177,7 +177,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
        struct sk_buff *skb;
        rxrpc_serial_t serial;
        rxrpc_seq_t hard_ack, top;
-       u8 flags;
+       bool last = false;
+       u8 subpacket;
        int ix;
 
        _enter("%d", call->debug_id);
@@ -189,30 +190,32 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
        hard_ack++;
        ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
        skb = call->rxtx_buffer[ix];
-       rxrpc_see_skb(skb, rxrpc_skb_rx_rotated);
+       rxrpc_see_skb(skb, rxrpc_skb_rotated);
        sp = rxrpc_skb(skb);
-       flags = sp->hdr.flags;
-       serial = sp->hdr.serial;
-       if (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO)
-               serial += (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO) - 1;
+
+       subpacket = call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
+       serial = sp->hdr.serial + subpacket;
+
+       if (subpacket == sp->nr_subpackets - 1 &&
+           sp->rx_flags & RXRPC_SKB_INCL_LAST)
+               last = true;
 
        call->rxtx_buffer[ix] = NULL;
        call->rxtx_annotations[ix] = 0;
        /* Barrier against rxrpc_input_data(). */
        smp_store_release(&call->rx_hard_ack, hard_ack);
 
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
 
-       _debug("%u,%u,%02x", hard_ack, top, flags);
        trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
-       if (flags & RXRPC_LAST_PACKET) {
+       if (last) {
                rxrpc_end_rx_phase(call, serial);
        } else {
                /* Check to see if there's an ACK that needs sending. */
                if (after_eq(hard_ack, call->ackr_consumed + 2) ||
                    after_eq(top, call->ackr_seen + 2) ||
                    (hard_ack == top && after(hard_ack, call->ackr_consumed)))
-                       rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial,
+                       rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
                                          true, true,
                                          rxrpc_propose_ack_rotate_rx);
                if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY)
@@ -233,18 +236,19 @@ static int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        rxrpc_seq_t seq = sp->hdr.seq;
        u16 cksum = sp->hdr.cksum;
+       u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
 
        _enter("");
 
        /* For all but the head jumbo subpacket, the security checksum is in a
         * jumbo header immediately prior to the data.
         */
-       if ((annotation & RXRPC_RX_ANNO_JUMBO) > 1) {
+       if (subpacket > 0) {
                __be16 tmp;
                if (skb_copy_bits(skb, offset - 2, &tmp, 2) < 0)
                        BUG();
                cksum = ntohs(tmp);
-               seq += (annotation & RXRPC_RX_ANNO_JUMBO) - 1;
+               seq += subpacket;
        }
 
        return call->conn->security->verify_packet(call, skb, offset, len,
@@ -265,19 +269,18 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
                             u8 *_annotation,
                             unsigned int *_offset, unsigned int *_len)
 {
+       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        unsigned int offset = sizeof(struct rxrpc_wire_header);
        unsigned int len;
        int ret;
        u8 annotation = *_annotation;
+       u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
 
        /* Locate the subpacket */
+       offset += subpacket * RXRPC_JUMBO_SUBPKTLEN;
        len = skb->len - offset;
-       if ((annotation & RXRPC_RX_ANNO_JUMBO) > 0) {
-               offset += (((annotation & RXRPC_RX_ANNO_JUMBO) - 1) *
-                          RXRPC_JUMBO_SUBPKTLEN);
-               len = (annotation & RXRPC_RX_ANNO_JLAST) ?
-                       skb->len - offset : RXRPC_JUMBO_SUBPKTLEN;
-       }
+       if (subpacket < sp->nr_subpackets - 1)
+               len = RXRPC_JUMBO_DATALEN;
 
        if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) {
                ret = rxrpc_verify_packet(call, skb, annotation, offset, len);
@@ -303,6 +306,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
 {
        struct rxrpc_skb_priv *sp;
        struct sk_buff *skb;
+       rxrpc_serial_t serial;
        rxrpc_seq_t hard_ack, top, seq;
        size_t remain;
        bool last;
@@ -336,12 +340,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
                        break;
                }
                smp_rmb();
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                sp = rxrpc_skb(skb);
 
-               if (!(flags & MSG_PEEK))
+               if (!(flags & MSG_PEEK)) {
+                       serial = sp->hdr.serial;
+                       serial += call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
                        trace_rxrpc_receive(call, rxrpc_receive_front,
-                                           sp->hdr.serial, seq);
+                                           serial, seq);
+               }
 
                if (msg)
                        sock_recv_timestamp(msg, sock->sk, skb);
index ae8cd89..c60c520 100644 (file)
@@ -187,10 +187,8 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
        struct rxrpc_skb_priv *sp;
        struct rxrpc_crypt iv;
        struct scatterlist sg[16];
-       struct sk_buff *trailer;
        unsigned int len;
        u16 check;
-       int nsg;
        int err;
 
        sp = rxrpc_skb(skb);
@@ -214,15 +212,14 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
        crypto_skcipher_encrypt(req);
 
        /* we want to encrypt the skbuff in-place */
-       nsg = skb_cow_data(skb, 0, &trailer);
-       err = -ENOMEM;
-       if (nsg < 0 || nsg > 16)
+       err = -EMSGSIZE;
+       if (skb_shinfo(skb)->nr_frags > 16)
                goto out;
 
        len = data_size + call->conn->size_align - 1;
        len &= ~(call->conn->size_align - 1);
 
-       sg_init_table(sg, nsg);
+       sg_init_table(sg, ARRAY_SIZE(sg));
        err = skb_to_sgvec(skb, sg, 0, len);
        if (unlikely(err < 0))
                goto out;
@@ -319,11 +316,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxkad_level1_hdr sechdr;
        struct rxrpc_crypt iv;
        struct scatterlist sg[16];
-       struct sk_buff *trailer;
        bool aborted;
        u32 data_size, buf;
        u16 check;
-       int nsg, ret;
+       int ret;
 
        _enter("");
 
@@ -336,11 +332,7 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
        /* Decrypt the skbuff in-place.  TODO: We really want to decrypt
         * directly into the target buffer.
         */
-       nsg = skb_cow_data(skb, 0, &trailer);
-       if (nsg < 0 || nsg > 16)
-               goto nomem;
-
-       sg_init_table(sg, nsg);
+       sg_init_table(sg, ARRAY_SIZE(sg));
        ret = skb_to_sgvec(skb, sg, offset, 8);
        if (unlikely(ret < 0))
                return ret;
@@ -388,10 +380,6 @@ protocol_error:
        if (aborted)
                rxrpc_send_abort_packet(call);
        return -EPROTO;
-
-nomem:
-       _leave(" = -ENOMEM");
-       return -ENOMEM;
 }
 
 /*
@@ -406,7 +394,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxkad_level2_hdr sechdr;
        struct rxrpc_crypt iv;
        struct scatterlist _sg[4], *sg;
-       struct sk_buff *trailer;
        bool aborted;
        u32 data_size, buf;
        u16 check;
@@ -423,12 +410,11 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        /* Decrypt the skbuff in-place.  TODO: We really want to decrypt
         * directly into the target buffer.
         */
-       nsg = skb_cow_data(skb, 0, &trailer);
-       if (nsg < 0)
-               goto nomem;
-
        sg = _sg;
-       if (unlikely(nsg > 4)) {
+       nsg = skb_shinfo(skb)->nr_frags;
+       if (nsg <= 4) {
+               nsg = 4;
+       } else {
                sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
                if (!sg)
                        goto nomem;
index bae1443..6a1547b 100644 (file)
@@ -176,7 +176,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
        skb->tstamp = ktime_get_real();
 
        ix = seq & RXRPC_RXTX_BUFF_MASK;
-       rxrpc_get_skb(skb, rxrpc_skb_tx_got);
+       rxrpc_get_skb(skb, rxrpc_skb_got);
        call->rxtx_annotations[ix] = annotation;
        smp_wmb();
        call->rxtx_buffer[ix] = skb;
@@ -248,7 +248,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
        }
 
 out:
-       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" = %d", ret);
        return ret;
 }
@@ -289,7 +289,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
        skb = call->tx_pending;
        call->tx_pending = NULL;
-       rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
+       rxrpc_see_skb(skb, rxrpc_skb_seen);
 
        copied = 0;
        do {
@@ -336,7 +336,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
                        if (!skb)
                                goto maybe_error;
 
-                       rxrpc_new_skb(skb, rxrpc_skb_tx_new);
+                       sp = rxrpc_skb(skb);
+                       sp->rx_flags |= RXRPC_SKB_TX_BUFFER;
+                       rxrpc_new_skb(skb, rxrpc_skb_new);
 
                        _debug("ALLOC SEND %p", skb);
 
@@ -346,7 +348,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
                        skb_reserve(skb, call->conn->security_size);
                        skb->len += call->conn->security_size;
 
-                       sp = rxrpc_skb(skb);
                        sp->remain = chunk;
                        if (sp->remain > skb_tailroom(skb))
                                sp->remain = skb_tailroom(skb);
@@ -439,7 +440,7 @@ out:
        return ret;
 
 call_terminated:
-       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" = %d", call->error);
        return call->error;
 
index 9ad5045..0348d2b 100644 (file)
@@ -14,7 +14,8 @@
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-#define select_skb_count(op) (op >= rxrpc_skb_tx_cleaned ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs)
+#define is_tx_skb(skb) (rxrpc_skb(skb)->rx_flags & RXRPC_SKB_TX_BUFFER)
+#define select_skb_count(skb) (is_tx_skb(skb) ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs)
 
 /*
  * Note the allocation or reception of a socket buffer.
@@ -22,8 +23,9 @@
 void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 {
        const void *here = __builtin_return_address(0);
-       int n = atomic_inc_return(select_skb_count(op));
-       trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
+       int n = atomic_inc_return(select_skb_count(skb));
+       trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
+                       rxrpc_skb(skb)->rx_flags, here);
 }
 
 /*
@@ -33,8 +35,9 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 {
        const void *here = __builtin_return_address(0);
        if (skb) {
-               int n = atomic_read(select_skb_count(op));
-               trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
+               int n = atomic_read(select_skb_count(skb));
+               trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
+                               rxrpc_skb(skb)->rx_flags, here);
        }
 }
 
@@ -44,11 +47,22 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 {
        const void *here = __builtin_return_address(0);
-       int n = atomic_inc_return(select_skb_count(op));
-       trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
+       int n = atomic_inc_return(select_skb_count(skb));
+       trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
+                       rxrpc_skb(skb)->rx_flags, here);
        skb_get(skb);
 }
 
+/*
+ * Note the dropping of a ref on a socket buffer by the core.
+ */
+void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
+{
+       const void *here = __builtin_return_address(0);
+       int n = atomic_inc_return(&rxrpc_n_rx_skbs);
+       trace_rxrpc_skb(skb, op, 0, n, 0, here);
+}
+
 /*
  * Note the destruction of a socket buffer.
  */
@@ -58,8 +72,9 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
        if (skb) {
                int n;
                CHECK_SLAB_OKAY(&skb->users);
-               n = atomic_dec_return(select_skb_count(op));
-               trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
+               n = atomic_dec_return(select_skb_count(skb));
+               trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
+                               rxrpc_skb(skb)->rx_flags, here);
                kfree_skb(skb);
        }
 }
@@ -72,9 +87,10 @@ void rxrpc_purge_queue(struct sk_buff_head *list)
        const void *here = __builtin_return_address(0);
        struct sk_buff *skb;
        while ((skb = skb_dequeue((list))) != NULL) {
-               int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged));
-               trace_rxrpc_skb(skb, rxrpc_skb_rx_purged,
-                               refcount_read(&skb->users), n, here);
+               int n = atomic_dec_return(select_skb_count(skb));
+               trace_rxrpc_skb(skb, rxrpc_skb_purged,
+                               refcount_read(&skb->users), n,
+                               rxrpc_skb(skb)->rx_flags, here);
                kfree_skb(skb);
        }
 }
index fd1f7e7..04b7bd4 100644 (file)
@@ -422,7 +422,7 @@ static __net_init int bpf_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, bpf_net_id);
 
-       return tc_action_net_init(tn, &act_bpf_ops);
+       return tc_action_net_init(net, tn, &act_bpf_ops);
 }
 
 static void __net_exit bpf_exit_net(struct list_head *net_list)
index 32ac04d..2b43cac 100644 (file)
@@ -231,7 +231,7 @@ static __net_init int connmark_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, connmark_net_id);
 
-       return tc_action_net_init(tn, &act_connmark_ops);
+       return tc_action_net_init(net, tn, &act_connmark_ops);
 }
 
 static void __net_exit connmark_exit_net(struct list_head *net_list)
index 9b92882..d3cfad8 100644 (file)
@@ -714,7 +714,7 @@ static __net_init int csum_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, csum_net_id);
 
-       return tc_action_net_init(tn, &act_csum_ops);
+       return tc_action_net_init(net, tn, &act_csum_ops);
 }
 
 static void __net_exit csum_exit_net(struct list_head *net_list)
index 33a1a74..cdd6f38 100644 (file)
@@ -939,7 +939,7 @@ static __net_init int ct_init_net(struct net *net)
                tn->labels = true;
        }
 
-       return tc_action_net_init(&tn->tn, &act_ct_ops);
+       return tc_action_net_init(net, &tn->tn, &act_ct_ops);
 }
 
 static void __net_exit ct_exit_net(struct list_head *net_list)
index 06ef74b..0dbcfd1 100644 (file)
@@ -376,7 +376,7 @@ static __net_init int ctinfo_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
 
-       return tc_action_net_init(tn, &act_ctinfo_ops);
+       return tc_action_net_init(net, tn, &act_ctinfo_ops);
 }
 
 static void __net_exit ctinfo_exit_net(struct list_head *net_list)
index 8f0140c..324f1d1 100644 (file)
@@ -278,7 +278,7 @@ static __net_init int gact_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, gact_net_id);
 
-       return tc_action_net_init(tn, &act_gact_ops);
+       return tc_action_net_init(net, tn, &act_gact_ops);
 }
 
 static void __net_exit gact_exit_net(struct list_head *net_list)
index 92ee853..3a31e24 100644 (file)
@@ -890,7 +890,7 @@ static __net_init int ife_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ife_net_id);
 
-       return tc_action_net_init(tn, &act_ife_ops);
+       return tc_action_net_init(net, tn, &act_ife_ops);
 }
 
 static void __net_exit ife_exit_net(struct list_head *net_list)
index ce2c30a..214a03d 100644 (file)
@@ -61,12 +61,13 @@ static int ipt_init_target(struct net *net, struct xt_entry_target *t,
        return 0;
 }
 
-static void ipt_destroy_target(struct xt_entry_target *t)
+static void ipt_destroy_target(struct xt_entry_target *t, struct net *net)
 {
        struct xt_tgdtor_param par = {
                .target   = t->u.kernel.target,
                .targinfo = t->data,
                .family   = NFPROTO_IPV4,
+               .net      = net,
        };
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
@@ -78,7 +79,7 @@ static void tcf_ipt_release(struct tc_action *a)
        struct tcf_ipt *ipt = to_ipt(a);
 
        if (ipt->tcfi_t) {
-               ipt_destroy_target(ipt->tcfi_t);
+               ipt_destroy_target(ipt->tcfi_t, a->idrinfo->net);
                kfree(ipt->tcfi_t);
        }
        kfree(ipt->tcfi_tname);
@@ -180,7 +181,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
 
        spin_lock_bh(&ipt->tcf_lock);
        if (ret != ACT_P_CREATED) {
-               ipt_destroy_target(ipt->tcfi_t);
+               ipt_destroy_target(ipt->tcfi_t, net);
                kfree(ipt->tcfi_tname);
                kfree(ipt->tcfi_t);
        }
@@ -350,7 +351,7 @@ static __net_init int ipt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, ipt_net_id);
 
-       return tc_action_net_init(tn, &act_ipt_ops);
+       return tc_action_net_init(net, tn, &act_ipt_ops);
 }
 
 static void __net_exit ipt_exit_net(struct list_head *net_list)
@@ -399,7 +400,7 @@ static __net_init int xt_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, xt_net_id);
 
-       return tc_action_net_init(tn, &act_xt_ops);
+       return tc_action_net_init(net, tn, &act_xt_ops);
 }
 
 static void __net_exit xt_exit_net(struct list_head *net_list)
index be3f88d..9d1bf50 100644 (file)
@@ -453,7 +453,7 @@ static __net_init int mirred_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, mirred_net_id);
 
-       return tc_action_net_init(tn, &act_mirred_ops);
+       return tc_action_net_init(net, tn, &act_mirred_ops);
 }
 
 static void __net_exit mirred_exit_net(struct list_head *net_list)
index 0f299e3..e168df0 100644 (file)
@@ -375,7 +375,7 @@ static __net_init int mpls_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, mpls_net_id);
 
-       return tc_action_net_init(tn, &act_mpls_ops);
+       return tc_action_net_init(net, tn, &act_mpls_ops);
 }
 
 static void __net_exit mpls_exit_net(struct list_head *net_list)
index 7b858c1..ea4c535 100644 (file)
@@ -327,7 +327,7 @@ static __net_init int nat_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, nat_net_id);
 
-       return tc_action_net_init(tn, &act_nat_ops);
+       return tc_action_net_init(net, tn, &act_nat_ops);
 }
 
 static void __net_exit nat_exit_net(struct list_head *net_list)
index 17360c6..cdfaa79 100644 (file)
@@ -498,7 +498,7 @@ static __net_init int pedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, pedit_net_id);
 
-       return tc_action_net_init(tn, &act_pedit_ops);
+       return tc_action_net_init(net, tn, &act_pedit_ops);
 }
 
 static void __net_exit pedit_exit_net(struct list_head *net_list)
index 49cec3e..6315e0f 100644 (file)
@@ -371,7 +371,7 @@ static __net_init int police_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, police_net_id);
 
-       return tc_action_net_init(tn, &act_police_ops);
+       return tc_action_net_init(net, tn, &act_police_ops);
 }
 
 static void __net_exit police_exit_net(struct list_head *net_list)
index 595308d..1022912 100644 (file)
@@ -102,13 +102,17 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
        goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
        s->rate = rate;
        s->psample_group_num = psample_group_num;
-       RCU_INIT_POINTER(s->psample_group, psample_group);
+       rcu_swap_protected(s->psample_group, psample_group,
+                          lockdep_is_held(&s->tcf_lock));
 
        if (tb[TCA_SAMPLE_TRUNC_SIZE]) {
                s->truncate = true;
                s->trunc_size = nla_get_u32(tb[TCA_SAMPLE_TRUNC_SIZE]);
        }
        spin_unlock_bh(&s->tcf_lock);
+
+       if (psample_group)
+               psample_group_put(psample_group);
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
 
@@ -265,7 +269,7 @@ static __net_init int sample_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, sample_net_id);
 
-       return tc_action_net_init(tn, &act_sample_ops);
+       return tc_action_net_init(net, tn, &act_sample_ops);
 }
 
 static void __net_exit sample_exit_net(struct list_head *net_list)
index 33aefa2..6120e56 100644 (file)
@@ -232,7 +232,7 @@ static __net_init int simp_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, simp_net_id);
 
-       return tc_action_net_init(tn, &act_simp_ops);
+       return tc_action_net_init(net, tn, &act_simp_ops);
 }
 
 static void __net_exit simp_exit_net(struct list_head *net_list)
index b100870..6a8d333 100644 (file)
@@ -307,6 +307,17 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
        return tcf_idr_search(tn, a, index);
 }
 
+static size_t tcf_skbedit_get_fill_size(const struct tc_action *act)
+{
+       return nla_total_size(sizeof(struct tc_skbedit))
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_PRIORITY */
+               + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING */
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MARK */
+               + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_PTYPE */
+               + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MASK */
+               + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */
+}
+
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
        .id             =       TCA_ID_SKBEDIT,
@@ -316,6 +327,7 @@ static struct tc_action_ops act_skbedit_ops = {
        .init           =       tcf_skbedit_init,
        .cleanup        =       tcf_skbedit_cleanup,
        .walk           =       tcf_skbedit_walker,
+       .get_fill_size  =       tcf_skbedit_get_fill_size,
        .lookup         =       tcf_skbedit_search,
        .size           =       sizeof(struct tcf_skbedit),
 };
@@ -324,7 +336,7 @@ static __net_init int skbedit_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 
-       return tc_action_net_init(tn, &act_skbedit_ops);
+       return tc_action_net_init(net, tn, &act_skbedit_ops);
 }
 
 static void __net_exit skbedit_exit_net(struct list_head *net_list)
index 7da3518..888437f 100644 (file)
@@ -287,7 +287,7 @@ static __net_init int skbmod_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 
-       return tc_action_net_init(tn, &act_skbmod_ops);
+       return tc_action_net_init(net, tn, &act_skbmod_ops);
 }
 
 static void __net_exit skbmod_exit_net(struct list_head *net_list)
index 6d0debd..2f83a79 100644 (file)
@@ -600,7 +600,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 
-       return tc_action_net_init(tn, &act_tunnel_key_ops);
+       return tc_action_net_init(net, tn, &act_tunnel_key_ops);
 }
 
 static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
index a3c9eea..287a30b 100644 (file)
@@ -334,7 +334,7 @@ static __net_init int vlan_init_net(struct net *net)
 {
        struct tc_action_net *tn = net_generic(net, vlan_net_id);
 
-       return tc_action_net_init(tn, &act_vlan_ops);
+       return tc_action_net_init(net, tn, &act_vlan_ops);
 }
 
 static void __net_exit vlan_exit_net(struct list_head *net_list)
index 04faee7..1047825 100644 (file)
@@ -1920,6 +1920,8 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
        cl = cops->find(q, portid);
        if (!cl)
                return;
+       if (!cops->tcf_block)
+               return;
        block = cops->tcf_block(q, cl, NULL);
        if (!block)
                return;
index 732e109..810645b 100644 (file)
@@ -181,11 +181,6 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)
        s64 credits;
        int len;
 
-       if (atomic64_read(&q->port_rate) == -1) {
-               WARN_ONCE(1, "cbs: dequeue() called with unknown port rate.");
-               return NULL;
-       }
-
        if (q->credits < 0) {
                credits = timediff_to_credits(now - q->last, q->idleslope);
 
@@ -303,11 +298,19 @@ static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q,
 static void cbs_set_port_rate(struct net_device *dev, struct cbs_sched_data *q)
 {
        struct ethtool_link_ksettings ecmd;
+       int speed = SPEED_10;
        int port_rate = -1;
+       int err;
+
+       err = __ethtool_get_link_ksettings(dev, &ecmd);
+       if (err < 0)
+               goto skip;
+
+       if (ecmd.base.speed != SPEED_UNKNOWN)
+               speed = ecmd.base.speed;
 
-       if (!__ethtool_get_link_ksettings(dev, &ecmd) &&
-           ecmd.base.speed != SPEED_UNKNOWN)
-               port_rate = ecmd.base.speed * 1000 * BYTES_PER_KBIT;
+skip:
+       port_rate = speed * 1000 * BYTES_PER_KBIT;
 
        atomic64_set(&q->port_rate, port_rate);
        netdev_dbg(dev, "cbs: set %s's port_rate to: %lld, linkspeed: %d\n",
index 11c03cf..ac28f6a 100644 (file)
@@ -46,6 +46,8 @@ EXPORT_SYMBOL(default_qdisc_ops);
  * - updates to tree and tree walking are only done under the rtnl mutex.
  */
 
+#define SKB_XOFF_MAGIC ((struct sk_buff *)1UL)
+
 static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q)
 {
        const struct netdev_queue *txq = q->dev_queue;
@@ -71,7 +73,7 @@ static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q)
                                q->q.qlen--;
                        }
                } else {
-                       skb = NULL;
+                       skb = SKB_XOFF_MAGIC;
                }
        }
 
@@ -253,8 +255,11 @@ validate:
                return skb;
 
        skb = qdisc_dequeue_skb_bad_txq(q);
-       if (unlikely(skb))
+       if (unlikely(skb)) {
+               if (skb == SKB_XOFF_MAGIC)
+                       return NULL;
                goto bulk;
+       }
        skb = q->dequeue(q);
        if (skb) {
 bulk:
@@ -624,8 +629,12 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,
 
        err = skb_array_produce(q, skb);
 
-       if (unlikely(err))
-               return qdisc_drop_cpu(skb, qdisc, to_free);
+       if (unlikely(err)) {
+               if (qdisc_is_percpu_stats(qdisc))
+                       return qdisc_drop_cpu(skb, qdisc, to_free);
+               else
+                       return qdisc_drop(skb, qdisc, to_free);
+       }
 
        qdisc_update_stats_at_enqueue(qdisc, pkt_len);
        return NET_XMIT_SUCCESS;
@@ -688,11 +697,14 @@ static void pfifo_fast_reset(struct Qdisc *qdisc)
                        kfree_skb(skb);
        }
 
-       for_each_possible_cpu(i) {
-               struct gnet_stats_queue *q = per_cpu_ptr(qdisc->cpu_qstats, i);
+       if (qdisc_is_percpu_stats(qdisc)) {
+               for_each_possible_cpu(i) {
+                       struct gnet_stats_queue *q;
 
-               q->backlog = 0;
-               q->qlen = 0;
+                       q = per_cpu_ptr(qdisc->cpu_qstats, i);
+                       q->backlog = 0;
+                       q->qlen = 0;
+               }
        }
 }
 
index cee6971..23cd1c8 100644 (file)
@@ -531,7 +531,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt,
                new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]);
 
        non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight;
-       if (non_hh_quantum > INT_MAX)
+       if (non_hh_quantum == 0 || non_hh_quantum > INT_MAX)
                return -EINVAL;
 
        sch_tree_lock(sch);
index c39db50..8d8bc2e 100644 (file)
@@ -477,11 +477,6 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
        u32 gate_mask;
        int i;
 
-       if (atomic64_read(&q->picos_per_byte) == -1) {
-               WARN_ONCE(1, "taprio: dequeue() called with unknown picos per byte.");
-               return NULL;
-       }
-
        rcu_read_lock();
        entry = rcu_dereference(q->current_entry);
        /* if there's no entry, it means that the schedule didn't
@@ -958,12 +953,20 @@ static void taprio_set_picos_per_byte(struct net_device *dev,
                                      struct taprio_sched *q)
 {
        struct ethtool_link_ksettings ecmd;
-       int picos_per_byte = -1;
+       int speed = SPEED_10;
+       int picos_per_byte;
+       int err;
 
-       if (!__ethtool_get_link_ksettings(dev, &ecmd) &&
-           ecmd.base.speed != SPEED_UNKNOWN)
-               picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8,
-                                          ecmd.base.speed * 1000 * 1000);
+       err = __ethtool_get_link_ksettings(dev, &ecmd);
+       if (err < 0)
+               goto skip;
+
+       if (ecmd.base.speed != SPEED_UNKNOWN)
+               speed = ecmd.base.speed;
+
+skip:
+       picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8,
+                                  speed * 1000 * 1000);
 
        atomic64_set(&q->picos_per_byte, picos_per_byte);
        netdev_dbg(dev, "taprio: set %s's picos_per_byte to: %lld, linkspeed: %d\n",
@@ -1195,7 +1198,8 @@ unlock:
        spin_unlock_bh(qdisc_lock(sch));
 
 free_sched:
-       kfree(new_admin);
+       if (new_admin)
+               call_rcu(&new_admin->rcu, taprio_free_sched_cb);
 
        return err;
 }
@@ -1248,6 +1252,10 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
         */
        q->clockid = -1;
 
+       spin_lock(&taprio_list_lock);
+       list_add(&q->taprio_list, &taprio_list);
+       spin_unlock(&taprio_list_lock);
+
        if (sch->parent != TC_H_ROOT)
                return -EOPNOTSUPP;
 
@@ -1265,10 +1273,6 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
        if (!opt)
                return -EINVAL;
 
-       spin_lock(&taprio_list_lock);
-       list_add(&q->taprio_list, &taprio_list);
-       spin_unlock(&taprio_list_lock);
-
        for (i = 0; i < dev->num_tx_queues; i++) {
                struct netdev_queue *dev_queue;
                struct Qdisc *qdisc;
index 2d47adc..53746ff 100644 (file)
@@ -1336,7 +1336,7 @@ static int __net_init sctp_ctrlsock_init(struct net *net)
        return status;
 }
 
-static void __net_init sctp_ctrlsock_exit(struct net *net)
+static void __net_exit sctp_ctrlsock_exit(struct net *net)
 {
        /* Free the control endpoint.  */
        inet_ctl_sock_destroy(net->sctp.ctl_sock);
index a554d6d..e52b212 100644 (file)
@@ -546,8 +546,8 @@ static void sctp_do_8_2_transport_strike(struct sctp_cmd_seq *commands,
         */
        if (net->sctp.pf_enable &&
           (transport->state == SCTP_ACTIVE) &&
-          (asoc->pf_retrans < transport->pathmaxrxt) &&
-          (transport->error_count > asoc->pf_retrans)) {
+          (transport->error_count < transport->pathmaxrxt) &&
+          (transport->error_count > transport->pf_retrans)) {
 
                sctp_assoc_control_transport(asoc, transport,
                                             SCTP_TRANSPORT_PF,
index 9d1f83b..b083d4e 100644 (file)
@@ -309,7 +309,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)
        return retval;
 }
 
-static long sctp_get_port_local(struct sock *, union sctp_addr *);
+static int sctp_get_port_local(struct sock *, union sctp_addr *);
 
 /* Verify this is a valid sockaddr. */
 static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
@@ -399,9 +399,8 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
         * detection.
         */
        addr->v4.sin_port = htons(snum);
-       if ((ret = sctp_get_port_local(sk, addr))) {
+       if (sctp_get_port_local(sk, addr))
                return -EADDRINUSE;
-       }
 
        /* Refresh ephemeral port.  */
        if (!bp->port)
@@ -413,11 +412,13 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        ret = sctp_add_bind_addr(bp, addr, af->sockaddr_len,
                                 SCTP_ADDR_SRC, GFP_ATOMIC);
 
-       /* Copy back into socket for getsockname() use. */
-       if (!ret) {
-               inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
-               sp->pf->to_sk_saddr(addr, sk);
+       if (ret) {
+               sctp_put_port(sk);
+               return ret;
        }
+       /* Copy back into socket for getsockname() use. */
+       inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
+       sp->pf->to_sk_saddr(addr, sk);
 
        return ret;
 }
@@ -7173,7 +7174,7 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
                val.spt_pathmaxrxt = trans->pathmaxrxt;
                val.spt_pathpfthld = trans->pf_retrans;
 
-               return 0;
+               goto out;
        }
 
        asoc = sctp_id2assoc(sk, val.spt_assoc_id);
@@ -7191,6 +7192,7 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
                val.spt_pathmaxrxt = sp->pathmaxrxt;
        }
 
+out:
        if (put_user(len, optlen) || copy_to_user(optval, &val, len))
                return -EFAULT;
 
@@ -7998,7 +8000,7 @@ static void sctp_unhash(struct sock *sk)
 static struct sctp_bind_bucket *sctp_bucket_create(
        struct sctp_bind_hashbucket *head, struct net *, unsigned short snum);
 
-static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
+static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
        struct sctp_sock *sp = sctp_sk(sk);
        bool reuse = (sk->sk_reuse || sp->reuse);
@@ -8108,7 +8110,7 @@ pp_found:
 
                        if (sctp_bind_addr_conflict(&ep2->base.bind_addr,
                                                    addr, sp2, sp)) {
-                               ret = (long)sk2;
+                               ret = 1;
                                goto fail_unlock;
                        }
                }
@@ -8180,7 +8182,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
        addr.v4.sin_port = htons(snum);
 
        /* Note: sk->sk_num gets filled in if ephemeral port request. */
-       return !!sctp_get_port_local(sk, &addr);
+       return sctp_get_port_local(sk, &addr);
 }
 
 /*
index 2594660..e83cdaa 100644 (file)
@@ -316,6 +316,7 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
                nstr_list[i] = htons(str_list[i]);
 
        if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
+               kfree(nstr_list);
                retval = -EAGAIN;
                goto out;
        }
index f0de323..6c8f09c 100644 (file)
@@ -76,13 +76,11 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
        struct smc_connection *conn = &smc->conn;
        struct sock *sk = &smc->sk;
-       bool noblock;
        long timeo;
        int rc = 0;
 
        /* similar to sk_stream_wait_memory */
        timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
-       noblock = timeo ? false : true;
        add_wait_queue(sk_sleep(sk), &wait);
        while (1) {
                sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
@@ -97,8 +95,8 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
                        break;
                }
                if (!timeo) {
-                       if (noblock)
-                               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+                       /* ensure EPOLLOUT is subsequently generated */
+                       set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                        rc = -EAGAIN;
                        break;
                }
index d8679b6..a07b516 100644 (file)
@@ -1970,6 +1970,7 @@ call_bind(struct rpc_task *task)
 static void
 call_bind_status(struct rpc_task *task)
 {
+       struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
        int status = -EIO;
 
        if (rpc_task_transmitted(task)) {
@@ -1977,14 +1978,15 @@ call_bind_status(struct rpc_task *task)
                return;
        }
 
-       if (task->tk_status >= 0) {
-               dprint_status(task);
+       dprint_status(task);
+       trace_rpc_bind_status(task);
+       if (task->tk_status >= 0)
+               goto out_next;
+       if (xprt_bound(xprt)) {
                task->tk_status = 0;
-               task->tk_action = call_connect;
-               return;
+               goto out_next;
        }
 
-       trace_rpc_bind_status(task);
        switch (task->tk_status) {
        case -ENOMEM:
                dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid);
@@ -2003,6 +2005,9 @@ call_bind_status(struct rpc_task *task)
                task->tk_rebind_retry--;
                rpc_delay(task, 3*HZ);
                goto retry_timeout;
+       case -ENOBUFS:
+               rpc_delay(task, HZ >> 2);
+               goto retry_timeout;
        case -EAGAIN:
                goto retry_timeout;
        case -ETIMEDOUT:
@@ -2026,7 +2031,6 @@ call_bind_status(struct rpc_task *task)
        case -ENETDOWN:
        case -EHOSTUNREACH:
        case -ENETUNREACH:
-       case -ENOBUFS:
        case -EPIPE:
                dprintk("RPC: %5u remote rpcbind unreachable: %d\n",
                                task->tk_pid, task->tk_status);
@@ -2043,7 +2047,9 @@ call_bind_status(struct rpc_task *task)
 
        rpc_call_rpcerror(task, status);
        return;
-
+out_next:
+       task->tk_action = call_connect;
+       return;
 retry_timeout:
        task->tk_status = 0;
        task->tk_action = call_bind;
@@ -2090,6 +2096,7 @@ call_connect(struct rpc_task *task)
 static void
 call_connect_status(struct rpc_task *task)
 {
+       struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
        struct rpc_clnt *clnt = task->tk_client;
        int status = task->tk_status;
 
@@ -2099,8 +2106,17 @@ call_connect_status(struct rpc_task *task)
        }
 
        dprint_status(task);
-
        trace_rpc_connect_status(task);
+
+       if (task->tk_status == 0) {
+               clnt->cl_stats->netreconn++;
+               goto out_next;
+       }
+       if (xprt_connected(xprt)) {
+               task->tk_status = 0;
+               goto out_next;
+       }
+
        task->tk_status = 0;
        switch (status) {
        case -ECONNREFUSED:
@@ -2117,8 +2133,6 @@ call_connect_status(struct rpc_task *task)
        case -ENETDOWN:
        case -ENETUNREACH:
        case -EHOSTUNREACH:
-       case -EADDRINUSE:
-       case -ENOBUFS:
        case -EPIPE:
                xprt_conditional_disconnect(task->tk_rqstp->rq_xprt,
                                            task->tk_rqstp->rq_connect_cookie);
@@ -2127,17 +2141,20 @@ call_connect_status(struct rpc_task *task)
                /* retry with existing socket, after a delay */
                rpc_delay(task, 3*HZ);
                /* fall through */
+       case -EADDRINUSE:
        case -ENOTCONN:
        case -EAGAIN:
        case -ETIMEDOUT:
                goto out_retry;
-       case 0:
-               clnt->cl_stats->netreconn++;
-               task->tk_action = call_transmit;
-               return;
+       case -ENOBUFS:
+               rpc_delay(task, HZ >> 2);
+               goto out_retry;
        }
        rpc_call_rpcerror(task, status);
        return;
+out_next:
+       task->tk_action = call_transmit;
+       return;
 out_retry:
        /* Check for timeouts before looping back to call_bind */
        task->tk_action = call_bind;
@@ -2365,7 +2382,7 @@ call_status(struct rpc_task *task)
        case -ECONNABORTED:
        case -ENOTCONN:
                rpc_force_rebind(clnt);
-               /* fall through */
+               break;
        case -EADDRINUSE:
                rpc_delay(task, 3*HZ);
                /* fall through */
index 783748d..2e71f54 100644 (file)
@@ -1408,13 +1408,6 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
                        status = -EBADMSG;
                        goto out_dequeue;
                }
-               if (task->tk_ops->rpc_call_prepare_transmit) {
-                       task->tk_ops->rpc_call_prepare_transmit(task,
-                                       task->tk_calldata);
-                       status = task->tk_status;
-                       if (status < 0)
-                               goto out_dequeue;
-               }
                if (RPC_SIGNALLED(task)) {
                        status = -ERESTARTSYS;
                        goto out_dequeue;
index b88d48d..0f1eaed 100644 (file)
@@ -75,6 +75,7 @@ void tipc_set_node_addr(struct net *net, u32 addr)
                tipc_set_node_id(net, node_id);
        }
        tn->trial_addr = addr;
+       tn->addr_trial_end = jiffies;
        pr_info("32-bit node address hash set to %x\n", addr);
 }
 
index 66d3a07..c2c5c53 100644 (file)
@@ -106,8 +106,6 @@ struct tipc_stats {
  * @transmitq: queue for sent, non-acked messages
  * @backlogq: queue for messages waiting to be sent
  * @snt_nxt: next sequence number to use for outbound messages
- * @prev_from: sequence number of most previous retransmission request
- * @stale_limit: time when repeated identical retransmits must force link reset
  * @ackers: # of peers that needs to ack each packet before it can be released
  * @acked: # last packet acked by a certain peer. Used for broadcast.
  * @rcv_nxt: next sequence number to expect for inbound messages
@@ -164,9 +162,7 @@ struct tipc_link {
                u16 limit;
        } backlog[5];
        u16 snd_nxt;
-       u16 prev_from;
        u16 window;
-       unsigned long stale_limit;
 
        /* Reception */
        u16 rcv_nxt;
@@ -1044,47 +1040,53 @@ static void tipc_link_advance_backlog(struct tipc_link *l,
  * link_retransmit_failure() - Detect repeated retransmit failures
  * @l: tipc link sender
  * @r: tipc link receiver (= l in case of unicast)
- * @from: seqno of the 1st packet in retransmit request
  * @rc: returned code
  *
  * Return: true if the repeated retransmit failures happens, otherwise
  * false
  */
 static bool link_retransmit_failure(struct tipc_link *l, struct tipc_link *r,
-                                   u16 from, int *rc)
+                                   int *rc)
 {
        struct sk_buff *skb = skb_peek(&l->transmq);
        struct tipc_msg *hdr;
 
        if (!skb)
                return false;
-       hdr = buf_msg(skb);
 
-       /* Detect repeated retransmit failures on same packet */
-       if (r->prev_from != from) {
-               r->prev_from = from;
-               r->stale_limit = jiffies + msecs_to_jiffies(r->tolerance);
-       } else if (time_after(jiffies, r->stale_limit)) {
-               pr_warn("Retransmission failure on link <%s>\n", l->name);
-               link_print(l, "State of link ");
-               pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n",
-                       msg_user(hdr), msg_type(hdr), msg_size(hdr),
-                       msg_errcode(hdr));
-               pr_info("sqno %u, prev: %x, src: %x\n",
-                       msg_seqno(hdr), msg_prevnode(hdr), msg_orignode(hdr));
-
-               trace_tipc_list_dump(&l->transmq, true, "retrans failure!");
-               trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!");
-               trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");
+       if (!TIPC_SKB_CB(skb)->retr_cnt)
+               return false;
 
-               if (link_is_bc_sndlink(l))
-                       *rc = TIPC_LINK_DOWN_EVT;
+       if (!time_after(jiffies, TIPC_SKB_CB(skb)->retr_stamp +
+                       msecs_to_jiffies(r->tolerance)))
+               return false;
+
+       hdr = buf_msg(skb);
+       if (link_is_bc_sndlink(l) && !less(r->acked, msg_seqno(hdr)))
+               return false;
 
+       pr_warn("Retransmission failure on link <%s>\n", l->name);
+       link_print(l, "State of link ");
+       pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n",
+               msg_user(hdr), msg_type(hdr), msg_size(hdr), msg_errcode(hdr));
+       pr_info("sqno %u, prev: %x, dest: %x\n",
+               msg_seqno(hdr), msg_prevnode(hdr), msg_destnode(hdr));
+       pr_info("retr_stamp %d, retr_cnt %d\n",
+               jiffies_to_msecs(TIPC_SKB_CB(skb)->retr_stamp),
+               TIPC_SKB_CB(skb)->retr_cnt);
+
+       trace_tipc_list_dump(&l->transmq, true, "retrans failure!");
+       trace_tipc_link_dump(l, TIPC_DUMP_NONE, "retrans failure!");
+       trace_tipc_link_dump(r, TIPC_DUMP_NONE, "retrans failure!");
+
+       if (link_is_bc_sndlink(l)) {
+               r->state = LINK_RESET;
+               *rc = TIPC_LINK_DOWN_EVT;
+       } else {
                *rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
-               return true;
        }
 
-       return false;
+       return true;
 }
 
 /* tipc_link_bc_retrans() - retransmit zero or more packets
@@ -1110,7 +1112,7 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
 
        trace_tipc_link_retrans(r, from, to, &l->transmq);
 
-       if (link_retransmit_failure(l, r, from, &rc))
+       if (link_retransmit_failure(l, r, &rc))
                return rc;
 
        skb_queue_walk(&l->transmq, skb) {
@@ -1119,11 +1121,10 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
                        continue;
                if (more(msg_seqno(hdr), to))
                        break;
-               if (link_is_bc_sndlink(l)) {
-                       if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
-                               continue;
-                       TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM;
-               }
+
+               if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
+                       continue;
+               TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM;
                _skb = __pskb_copy(skb, LL_MAX_HEADER + MIN_H_SIZE, GFP_ATOMIC);
                if (!_skb)
                        return 0;
@@ -1133,6 +1134,10 @@ static int tipc_link_bc_retrans(struct tipc_link *l, struct tipc_link *r,
                _skb->priority = TC_PRIO_CONTROL;
                __skb_queue_tail(xmitq, _skb);
                l->stats.retransmitted++;
+
+               /* Increase actual retrans counter & mark first time */
+               if (!TIPC_SKB_CB(skb)->retr_cnt++)
+                       TIPC_SKB_CB(skb)->retr_stamp = jiffies;
        }
        return 0;
 }
@@ -1357,12 +1362,10 @@ static int tipc_link_advance_transmq(struct tipc_link *l, u16 acked, u16 gap,
        struct tipc_msg *hdr;
        u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1;
        u16 ack = l->rcv_nxt - 1;
+       bool passed = false;
        u16 seqno, n = 0;
        int rc = 0;
 
-       if (gap && link_retransmit_failure(l, l, acked + 1, &rc))
-               return rc;
-
        skb_queue_walk_safe(&l->transmq, skb, tmp) {
                seqno = buf_seqno(skb);
 
@@ -1372,12 +1375,17 @@ next_gap_ack:
                        __skb_unlink(skb, &l->transmq);
                        kfree_skb(skb);
                } else if (less_eq(seqno, acked + gap)) {
-                       /* retransmit skb */
+                       /* First, check if repeated retrans failures occurs? */
+                       if (!passed && link_retransmit_failure(l, l, &rc))
+                               return rc;
+                       passed = true;
+
+                       /* retransmit skb if unrestricted*/
                        if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
                                continue;
                        TIPC_SKB_CB(skb)->nxt_retr = TIPC_UC_RETR_TIME;
-
-                       _skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC);
+                       _skb = __pskb_copy(skb, LL_MAX_HEADER + MIN_H_SIZE,
+                                          GFP_ATOMIC);
                        if (!_skb)
                                continue;
                        hdr = buf_msg(_skb);
@@ -1386,6 +1394,10 @@ next_gap_ack:
                        _skb->priority = TC_PRIO_CONTROL;
                        __skb_queue_tail(xmitq, _skb);
                        l->stats.retransmitted++;
+
+                       /* Increase actual retrans counter & mark first time */
+                       if (!TIPC_SKB_CB(skb)->retr_cnt++)
+                               TIPC_SKB_CB(skb)->retr_stamp = jiffies;
                } else {
                        /* retry with Gap ACK blocks if any */
                        if (!ga || n >= ga->gack_cnt)
@@ -2577,7 +2589,7 @@ int tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf)
        i += scnprintf(buf + i, sz - i, " %x", l->peer_caps);
        i += scnprintf(buf + i, sz - i, " %u", l->silent_intv_cnt);
        i += scnprintf(buf + i, sz - i, " %u", l->rst_cnt);
-       i += scnprintf(buf + i, sz - i, " %u", l->prev_from);
+       i += scnprintf(buf + i, sz - i, " %u", 0);
        i += scnprintf(buf + i, sz - i, " %u", 0);
        i += scnprintf(buf + i, sz - i, " %u", l->acked);
 
index da509f0..d7ebc9e 100644 (file)
@@ -102,13 +102,15 @@ struct plist;
 #define TIPC_MEDIA_INFO_OFFSET 5
 
 struct tipc_skb_cb {
-       u32 bytes_read;
-       u32 orig_member;
        struct sk_buff *tail;
        unsigned long nxt_retr;
-       bool validated;
+       unsigned long retr_stamp;
+       u32 bytes_read;
+       u32 orig_member;
        u16 chain_imp;
        u16 ackers;
+       u16 retr_cnt;
+       bool validated;
 };
 
 #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
index 44abc8e..241ed22 100644 (file)
@@ -223,7 +223,8 @@ static void tipc_publ_purge(struct net *net, struct publication *publ, u32 addr)
                       publ->key);
        }
 
-       kfree_rcu(p, rcu);
+       if (p)
+               kfree_rcu(p, rcu);
 }
 
 /**
index 7c0b2b7..43922d8 100644 (file)
@@ -373,9 +373,9 @@ static int tls_push_data(struct sock *sk,
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_prot_info *prot = &tls_ctx->prot_info;
        struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
-       int tls_push_record_flags = flags | MSG_SENDPAGE_NOTLAST;
        int more = flags & (MSG_SENDPAGE_NOTLAST | MSG_MORE);
        struct tls_record_info *record = ctx->open_record;
+       int tls_push_record_flags;
        struct page_frag *pfrag;
        size_t orig_size = size;
        u32 max_open_record_len;
@@ -390,6 +390,9 @@ static int tls_push_data(struct sock *sk,
        if (sk->sk_err)
                return -sk->sk_err;
 
+       flags |= MSG_SENDPAGE_DECRYPTED;
+       tls_push_record_flags = flags | MSG_SENDPAGE_NOTLAST;
+
        timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
        if (tls_is_partially_sent_record(tls_ctx)) {
                rc = tls_push_partial_record(sk, tls_ctx, flags);
@@ -576,7 +579,9 @@ void tls_device_write_space(struct sock *sk, struct tls_context *ctx)
                gfp_t sk_allocation = sk->sk_allocation;
 
                sk->sk_allocation = GFP_ATOMIC;
-               tls_push_partial_record(sk, ctx, MSG_DONTWAIT | MSG_NOSIGNAL);
+               tls_push_partial_record(sk, ctx,
+                                       MSG_DONTWAIT | MSG_NOSIGNAL |
+                                       MSG_SENDPAGE_DECRYPTED);
                sk->sk_allocation = sk_allocation;
        }
 }
index 9cbbae6..43252a8 100644 (file)
@@ -308,6 +308,8 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
        if (free_ctx)
                icsk->icsk_ulp_data = NULL;
        sk->sk_prot = ctx->sk_proto;
+       if (sk->sk_write_space == tls_write_space)
+               sk->sk_write_space = ctx->sk_write_space;
        write_unlock_bh(&sk->sk_callback_lock);
        release_sock(sk);
        if (ctx->tx_conf == TLS_SW)
index 4831ad7..327479c 100644 (file)
@@ -2788,7 +2788,7 @@ static void reg_process_pending_hints(void)
 
        /* When last_request->processed becomes true this will be rescheduled */
        if (lr && !lr->processed) {
-               reg_process_hint(lr);
+               pr_debug("Pending regulatory request, waiting for it to be processed...\n");
                return;
        }
 
index d0e35b7..e748378 100644 (file)
@@ -233,25 +233,30 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
+               /* Extended Key ID can only be used with CCMP/GCMP ciphers */
+               if ((pairwise && key_idx) ||
+                   params->mode != NL80211_KEY_RX_TX)
+                       return -EINVAL;
+               break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_GCMP_256:
-               /* IEEE802.11-2016 allows only 0 and - when using Extended Key
-                * ID - 1 as index for pairwise keys.
+               /* IEEE802.11-2016 allows only 0 and - when supporting
+                * Extended Key ID - 1 as index for pairwise keys.
                 * @NL80211_KEY_NO_TX is only allowed for pairwise keys when
                 * the driver supports Extended Key ID.
                 * @NL80211_KEY_SET_TX can't be set when installing and
                 * validating a key.
                 */
-               if (params->mode == NL80211_KEY_NO_TX) {
-                       if (!wiphy_ext_feature_isset(&rdev->wiphy,
-                                                    NL80211_EXT_FEATURE_EXT_KEY_ID))
-                               return -EINVAL;
-                       else if (!pairwise || key_idx < 0 || key_idx > 1)
+               if ((params->mode == NL80211_KEY_NO_TX && !pairwise) ||
+                   params->mode == NL80211_KEY_SET_TX)
+                       return -EINVAL;
+               if (wiphy_ext_feature_isset(&rdev->wiphy,
+                                           NL80211_EXT_FEATURE_EXT_KEY_ID)) {
+                       if (pairwise && (key_idx < 0 || key_idx > 1))
                                return -EINVAL;
-               } else if ((pairwise && key_idx) ||
-                          params->mode == NL80211_KEY_SET_TX) {
+               } else if (pairwise && key_idx) {
                        return -EINVAL;
                }
                break;
index 83de74c..688aac7 100644 (file)
@@ -365,7 +365,7 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
        umem->pages = kcalloc(umem->npgs, sizeof(*umem->pages), GFP_KERNEL);
        if (!umem->pages) {
                err = -ENOMEM;
-               goto out_account;
+               goto out_pin;
        }
 
        for (i = 0; i < umem->npgs; i++)
@@ -373,6 +373,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
 
        return 0;
 
+out_pin:
+       xdp_umem_unpin_pages(umem);
 out_account:
        xdp_umem_unaccount_pages(umem);
        return err;
index 74868f9..2ab4859 100644 (file)
@@ -145,8 +145,6 @@ static int xfrmi_create(struct net_device *dev)
        if (err < 0)
                goto out;
 
-       strcpy(xi->p.name, dev->name);
-
        dev_hold(dev);
        xfrmi_link(xfrmn, xi);
 
@@ -177,7 +175,6 @@ static void xfrmi_dev_uninit(struct net_device *dev)
        struct xfrmi_net *xfrmn = net_generic(xi->net, xfrmi_net_id);
 
        xfrmi_unlink(xfrmn, xi);
-       dev_put(xi->phydev);
        dev_put(dev);
 }
 
@@ -294,7 +291,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        if (tdev == dev) {
                stats->collisions++;
                net_warn_ratelimited("%s: Local routing loop detected!\n",
-                                    xi->p.name);
+                                    dev->name);
                goto tx_err_dst_release;
        }
 
@@ -364,7 +361,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_err;
        }
 
-       fl.flowi_oif = xi->phydev->ifindex;
+       fl.flowi_oif = xi->p.link;
 
        ret = xfrmi_xmit2(skb, dev, &fl);
        if (ret < 0)
@@ -505,7 +502,7 @@ static int xfrmi_change(struct xfrm_if *xi, const struct xfrm_if_parms *p)
 
 static int xfrmi_update(struct xfrm_if *xi, struct xfrm_if_parms *p)
 {
-       struct net *net = dev_net(xi->dev);
+       struct net *net = xi->net;
        struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
        int err;
 
@@ -550,7 +547,7 @@ static int xfrmi_get_iflink(const struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
 
-       return xi->phydev->ifindex;
+       return xi->p.link;
 }
 
 
@@ -576,12 +573,14 @@ static void xfrmi_dev_setup(struct net_device *dev)
        dev->needs_free_netdev  = true;
        dev->priv_destructor    = xfrmi_dev_free;
        netif_keep_dst(dev);
+
+       eth_broadcast_addr(dev->broadcast);
 }
 
 static int xfrmi_dev_init(struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net_device *phydev = xi->phydev;
+       struct net_device *phydev = __dev_get_by_index(xi->net, xi->p.link);
        int err;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
@@ -596,13 +595,19 @@ static int xfrmi_dev_init(struct net_device *dev)
 
        dev->features |= NETIF_F_LLTX;
 
-       dev->needed_headroom = phydev->needed_headroom;
-       dev->needed_tailroom = phydev->needed_tailroom;
+       if (phydev) {
+               dev->needed_headroom = phydev->needed_headroom;
+               dev->needed_tailroom = phydev->needed_tailroom;
 
-       if (is_zero_ether_addr(dev->dev_addr))
-               eth_hw_addr_inherit(dev, phydev);
-       if (is_zero_ether_addr(dev->broadcast))
-               memcpy(dev->broadcast, phydev->broadcast, dev->addr_len);
+               if (is_zero_ether_addr(dev->dev_addr))
+                       eth_hw_addr_inherit(dev, phydev);
+               if (is_zero_ether_addr(dev->broadcast))
+                       memcpy(dev->broadcast, phydev->broadcast,
+                              dev->addr_len);
+       } else {
+               eth_hw_addr_random(dev);
+               eth_broadcast_addr(dev->broadcast);
+       }
 
        return 0;
 }
@@ -638,12 +643,6 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
        int err;
 
        xfrmi_netlink_parms(data, &p);
-
-       if (!tb[IFLA_IFNAME])
-               return -EINVAL;
-
-       nla_strlcpy(p.name, tb[IFLA_IFNAME], IFNAMSIZ);
-
        xi = xfrmi_locate(net, &p);
        if (xi)
                return -EEXIST;
@@ -652,13 +651,8 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
        xi->p = p;
        xi->net = net;
        xi->dev = dev;
-       xi->phydev = dev_get_by_index(net, p.link);
-       if (!xi->phydev)
-               return -ENODEV;
 
        err = xfrmi_create(dev);
-       if (err < 0)
-               dev_put(xi->phydev);
        return err;
 }
 
@@ -672,11 +666,11 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
                           struct netlink_ext_ack *extack)
 {
        struct xfrm_if *xi = netdev_priv(dev);
-       struct net *net = dev_net(dev);
-
-       xfrmi_netlink_parms(data, &xi->p);
+       struct net *net = xi->net;
+       struct xfrm_if_parms p;
 
-       xi = xfrmi_locate(net, &xi->p);
+       xfrmi_netlink_parms(data, &p);
+       xi = xfrmi_locate(net, &p);
        if (!xi) {
                xi = netdev_priv(dev);
        } else {
@@ -684,7 +678,7 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
                        return -EEXIST;
        }
 
-       return xfrmi_update(xi, &xi->p);
+       return xfrmi_update(xi, &p);
 }
 
 static size_t xfrmi_get_size(const struct net_device *dev)
@@ -715,7 +709,7 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev)
 {
        struct xfrm_if *xi = netdev_priv(dev);
 
-       return dev_net(xi->phydev);
+       return xi->net;
 }
 
 static const struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
index 8ca637a..21e9392 100644 (file)
@@ -912,6 +912,7 @@ restart:
                } else if (delta > 0) {
                        p = &parent->rb_right;
                } else {
+                       bool same_prefixlen = node->prefixlen == n->prefixlen;
                        struct xfrm_policy *tmp;
 
                        hlist_for_each_entry(tmp, &n->hhead, bydst) {
@@ -919,9 +920,11 @@ restart:
                                hlist_del_rcu(&tmp->bydst);
                        }
 
+                       node->prefixlen = prefixlen;
+
                        xfrm_policy_inexact_list_reinsert(net, node, family);
 
-                       if (node->prefixlen == n->prefixlen) {
+                       if (same_prefixlen) {
                                kfree_rcu(n, rcu);
                                return;
                        }
@@ -929,7 +932,6 @@ restart:
                        rb_erase(*p, new);
                        kfree_rcu(n, rcu);
                        n = node;
-                       n->prefixlen = prefixlen;
                        goto restart;
                }
        }
@@ -3269,7 +3271,7 @@ decode_session4(struct sk_buff *skb, struct flowi *fl, bool reverse)
        struct flowi4 *fl4 = &fl->u.ip4;
        int oif = 0;
 
-       if (skb_dst(skb))
+       if (skb_dst(skb) && skb_dst(skb)->dev)
                oif = skb_dst(skb)->dev->ifindex;
 
        memset(fl4, 0, sizeof(struct flowi4));
@@ -3387,7 +3389,7 @@ decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse)
 
        nexthdr = nh[nhoff];
 
-       if (skb_dst(skb))
+       if (skb_dst(skb) && skb_dst(skb)->dev)
                oif = skb_dst(skb)->dev->ifindex;
 
        memset(fl6, 0, sizeof(struct flowi6));
index 85571e9..bfeab44 100644 (file)
@@ -245,7 +245,7 @@ int main(int argc, char *argv[])
 
        if (argc != 2) {
                printf(
-                       "Sintax:  %s fbdev\n"
+                       "Syntax:  %s fbdev\n"
                        "Usually: /dev/fb0, /dev/fb1...\n", argv[0]);
                return -1;
        }
index 6410bd2..03757cc 100644 (file)
@@ -1,4 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
+ifdef CONFIG_KASAN
+CFLAGS_KASAN_NOSANITIZE := -fno-builtin
+KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
+endif
+
 ifdef CONFIG_KASAN_GENERIC
 
 ifdef CONFIG_KASAN_INLINE
@@ -7,8 +12,6 @@ else
        call_threshold := 0
 endif
 
-KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
-
 CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
 
 cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
@@ -45,7 +48,3 @@ CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
                $(instrumentation_flags)
 
 endif # CONFIG_KASAN_SW_TAGS
-
-ifdef CONFIG_KASAN
-CFLAGS_KASAN_NOSANITIZE := -fno-builtin
-endif
index 988120e..0f78d94 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 // Check if refcount_t type and API should be used
 // instead of atomic_t type when dealing with refcounters
 //
diff --git a/scripts/tools-support-relr.sh b/scripts/tools-support-relr.sh
new file mode 100755 (executable)
index 0000000..97a2c84
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh -eu
+# SPDX-License-Identifier: GPL-2.0
+
+tmp_file=$(mktemp)
+trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT
+
+cat << "END" | "$CC" -c -x c - -o $tmp_file.o >/dev/null 2>&1
+void *p = &p;
+END
+"$LD" $tmp_file.o -shared -Bsymbolic --pack-dyn-relocs=relr -o $tmp_file
+
+# Despite printing an error message, GNU nm still exits with exit code 0 if it
+# sees a relr section. So we need to check that nothing is printed to stderr.
+test -z "$("$NM" $tmp_file 2>&1 >/dev/null)"
+
+"$OBJCOPY" -O binary $tmp_file $tmp_file.bin
index 7325f38..957b9e3 100644 (file)
@@ -595,7 +595,7 @@ struct key *request_key_and_link(struct key_type *type,
 
        key = check_cached_key(&ctx);
        if (key)
-               return key;
+               goto error_free;
 
        /* search all the process keyrings for a key */
        rcu_read_lock();
index e73ec04..ecba39c 100644 (file)
@@ -66,6 +66,9 @@ static void request_key_auth_describe(const struct key *key,
 {
        struct request_key_auth *rka = dereference_key_rcu(key);
 
+       if (!rka)
+               return;
+
        seq_puts(m, "key:");
        seq_puts(m, key->description);
        if (key_is_positive(key))
@@ -83,6 +86,9 @@ static long request_key_auth_read(const struct key *key,
        size_t datalen;
        long ret;
 
+       if (!rka)
+               return -EKEYREVOKED;
+
        datalen = rka->callout_len;
        ret = datalen;
 
index 9a94672..ade6991 100644 (file)
@@ -1228,24 +1228,11 @@ hashalg_fail:
 
 static int __init init_digests(void)
 {
-       u8 digest[TPM_MAX_DIGEST_SIZE];
-       int ret;
-       int i;
-
-       ret = tpm_get_random(chip, digest, TPM_MAX_DIGEST_SIZE);
-       if (ret < 0)
-               return ret;
-       if (ret < TPM_MAX_DIGEST_SIZE)
-               return -EFAULT;
-
        digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
                          GFP_KERNEL);
        if (!digests)
                return -ENOMEM;
 
-       for (i = 0; i < chip->nr_allocated_banks; i++)
-               memcpy(digests[i].digest, digest, TPM_MAX_DIGEST_SIZE);
-
        return 0;
 }
 
index 7737b26..6d9592f 100644 (file)
@@ -1835,8 +1835,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
        if (cptr->type == USER_CLIENT) {
                info->input_pool = cptr->data.user.fifo_pool_size;
                info->input_free = info->input_pool;
-               if (cptr->data.user.fifo)
-                       info->input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
+               info->input_free = snd_seq_fifo_unused_cells(cptr->data.user.fifo);
        } else {
                info->input_pool = 0;
                info->input_free = 0;
index ea69261..eaaa8b5 100644 (file)
@@ -263,3 +263,20 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
 
        return 0;
 }
+
+/* get the number of unused cells safely */
+int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
+{
+       unsigned long flags;
+       int cells;
+
+       if (!f)
+               return 0;
+
+       snd_use_lock_use(&f->use_lock);
+       spin_lock_irqsave(&f->lock, flags);
+       cells = snd_seq_unused_cells(f->pool);
+       spin_unlock_irqrestore(&f->lock, flags);
+       snd_use_lock_free(&f->use_lock);
+       return cells;
+}
index edc6874..b56a7b8 100644 (file)
@@ -53,5 +53,7 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file, poll_table
 /* resize pool in fifo */
 int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize);
 
+/* get the number of unused cells safely */
+int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f);
 
 #endif
index 9ea3934..7c6d1c2 100644 (file)
@@ -248,7 +248,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
                unsigned int channels = params_channels(hw_params);
 
                mutex_lock(&oxfw->mutex);
-               err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
+               err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
                                                     rate, channels);
                if (err >= 0)
                        ++oxfw->substreams_count;
index 92390d4..18e6546 100644 (file)
@@ -824,6 +824,8 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
        while (id >= 0) {
                const struct hda_fixup *fix = codec->fixup_list + id;
 
+               if (++depth > 10)
+                       break;
                if (fix->chained_before)
                        apply_fixup(codec, fix->chain_id, action, depth + 1);
 
@@ -863,8 +865,6 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
                }
                if (!fix->chained || fix->chained_before)
                        break;
-               if (++depth > 10)
-                       break;
                id = fix->chain_id;
        }
 }
index 485edab..10d5023 100644 (file)
@@ -6009,7 +6009,8 @@ int snd_hda_gen_init(struct hda_codec *codec)
        if (spec->init_hook)
                spec->init_hook(codec);
 
-       snd_hda_apply_verbs(codec);
+       if (!spec->skip_verbs)
+               snd_hda_apply_verbs(codec);
 
        init_multi_out(codec);
        init_extra_out(codec);
@@ -6051,6 +6052,24 @@ void snd_hda_gen_free(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hda_gen_free);
 
+/**
+ * snd_hda_gen_reboot_notify - Make codec enter D3 before rebooting
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops reboot_notify function.
+ */
+void snd_hda_gen_reboot_notify(struct hda_codec *codec)
+{
+       /* Make the codec enter D3 to avoid spurious noises from the internal
+        * speaker during (and after) reboot
+        */
+       snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       msleep(10);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_reboot_notify);
+
 #ifdef CONFIG_PM
 /**
  * snd_hda_gen_check_power_status - check the loopback power save state
@@ -6078,6 +6097,7 @@ static const struct hda_codec_ops generic_patch_ops = {
        .init = snd_hda_gen_init,
        .free = snd_hda_gen_free,
        .unsol_event = snd_hda_jack_unsol_event,
+       .reboot_notify = snd_hda_gen_reboot_notify,
 #ifdef CONFIG_PM
        .check_power_status = snd_hda_gen_check_power_status,
 #endif
@@ -6100,7 +6120,7 @@ static int snd_hda_parse_generic_codec(struct hda_codec *codec)
 
        err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
        if (err < 0)
-               return err;
+               goto error;
 
        err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
        if (err < 0)
index 35a670a..fb9f1a9 100644 (file)
@@ -243,6 +243,7 @@ struct hda_gen_spec {
        unsigned int indep_hp_enabled:1; /* independent HP enabled */
        unsigned int have_aamix_ctl:1;
        unsigned int hp_mic_jack_modes:1;
+       unsigned int skip_verbs:1; /* don't apply verbs at snd_hda_gen_init() */
 
        /* additional mute flags (only effective with auto_mute_via_amp=1) */
        u64 mute_bits;
@@ -332,6 +333,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
                                  struct auto_pin_cfg *cfg);
 int snd_hda_gen_build_controls(struct hda_codec *codec);
 int snd_hda_gen_build_pcms(struct hda_codec *codec);
+void snd_hda_gen_reboot_notify(struct hda_codec *codec);
 
 /* standard jack event callbacks */
 void snd_hda_gen_hp_automute(struct hda_codec *codec,
index a6d8c0d..99fc091 100644 (file)
@@ -2508,6 +2508,9 @@ static const struct pci_device_id azx_ids[] = {
        /* AMD, X370 & co */
        { PCI_DEVICE(0x1022, 0x1457),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
+       /* AMD, X570 & co */
+       { PCI_DEVICE(0x1022, 0x1487),
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
        /* AMD Stoney */
        { PCI_DEVICE(0x1022, 0x157a),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
index 0d51823..6d1fb7c 100644 (file)
@@ -1175,6 +1175,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
        SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE),
        SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ),
        SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ),
+       SND_PCI_QUIRK(0x1102, 0x0027, "Sound Blaster Z", QUIRK_SBZ),
        SND_PCI_QUIRK(0x1102, 0x0033, "Sound Blaster ZxR", QUIRK_SBZ),
        SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
        SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
index f299f13..968d3ca 100644 (file)
@@ -163,23 +163,10 @@ static void cx_auto_reboot_notify(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
 
-       switch (codec->core.vendor_id) {
-       case 0x14f12008: /* CX8200 */
-       case 0x14f150f2: /* CX20722 */
-       case 0x14f150f4: /* CX20724 */
-               break;
-       default:
-               return;
-       }
-
        /* Turn the problematic codec into D3 to avoid spurious noises
           from the internal speaker during (and after) reboot */
        cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
-
-       snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       msleep(10);
+       snd_hda_gen_reboot_notify(codec);
 }
 
 static void cx_auto_free(struct hda_codec *codec)
@@ -624,18 +611,20 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
 
 /* update LED status via GPIO */
 static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
-                               bool enabled)
+                               bool led_on)
 {
        struct conexant_spec *spec = codec->spec;
        unsigned int oldval = spec->gpio_led;
 
        if (spec->mute_led_polarity)
-               enabled = !enabled;
+               led_on = !led_on;
 
-       if (enabled)
-               spec->gpio_led &= ~mask;
-       else
+       if (led_on)
                spec->gpio_led |= mask;
+       else
+               spec->gpio_led &= ~mask;
+       codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
+                       mask, led_on, spec->gpio_led);
        if (spec->gpio_led != oldval)
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
                                    spec->gpio_led);
@@ -646,8 +635,8 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
 {
        struct hda_codec *codec = private_data;
        struct conexant_spec *spec = codec->spec;
-
-       cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+       /* muted -> LED on */
+       cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, !enabled);
 }
 
 /* turn on/off mic-mute LED via GPIO per capture hook */
@@ -669,7 +658,6 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
                { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
                {}
        };
-       codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
index de224cb..c1ddfd2 100644 (file)
@@ -837,9 +837,11 @@ static int alc_init(struct hda_codec *codec)
        if (spec->init_hook)
                spec->init_hook(codec);
 
+       spec->gen.skip_verbs = 1; /* applied in below */
        snd_hda_gen_init(codec);
        alc_fix_pll(codec);
        alc_auto_init_amp(codec, spec->init_amp);
+       snd_hda_apply_verbs(codec); /* apply verbs here after own init */
 
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
 
@@ -869,15 +871,6 @@ static void alc_reboot_notify(struct hda_codec *codec)
                alc_shutup(codec);
 }
 
-/* power down codec to D3 at reboot/shutdown; set as reboot_notify ops */
-static void alc_d3_at_reboot(struct hda_codec *codec)
-{
-       snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       msleep(10);
-}
-
 #define alc_free       snd_hda_gen_free
 
 #ifdef CONFIG_PM
@@ -5152,7 +5145,7 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */
+               spec->reboot_notify = snd_hda_gen_reboot_notify; /* reduce noise */
                spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
                codec->power_save_node = 0; /* avoid click noises */
                snd_hda_apply_pincfgs(codec, pincfgs);
@@ -5806,6 +5799,7 @@ enum {
        ALC286_FIXUP_ACER_AIO_HEADSET_MIC,
        ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
        ALC299_FIXUP_PREDATOR_SPK,
+       ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -6846,6 +6840,16 @@ static const struct hda_fixup alc269_fixups[] = {
                        { }
                }
        },
+       [ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x411111f0 }, /* disable confusing internal speaker */
+                       { 0x19, 0x04a11150 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6987,6 +6991,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x82bf, "HP G3 mini", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x82c0, "HP G3 mini premium", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -7003,6 +7009,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
        SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
@@ -7080,6 +7087,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
        SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x3151, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
@@ -8954,6 +8962,7 @@ static int patch_alc680(struct hda_codec *codec)
 static const struct hda_device_id snd_hda_id_realtek[] = {
        HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
index 54ac2fd..67f06c9 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 33eb725..05db311 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/dmi.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 4977b5a..9d65742 100644 (file)
@@ -8,6 +8,7 @@
  *          Mengdong Lin <mengdong.lin@intel.com>
  */
 
+#include <linux/gpio/consumer.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
index 2c03e0f..f70211e 100644 (file)
@@ -550,6 +550,15 @@ int line6_init_pcm(struct usb_line6 *line6,
        line6pcm->volume_monitor = 255;
        line6pcm->line6 = line6;
 
+       spin_lock_init(&line6pcm->out.lock);
+       spin_lock_init(&line6pcm->in.lock);
+       line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
+
+       line6->line6pcm = line6pcm;
+
+       pcm->private_data = line6pcm;
+       pcm->private_free = line6_cleanup_pcm;
+
        line6pcm->max_packet_size_in =
                usb_maxpacket(line6->usbdev,
                        usb_rcvisocpipe(line6->usbdev, ep_read), 0);
@@ -562,15 +571,6 @@ int line6_init_pcm(struct usb_line6 *line6,
                return -EINVAL;
        }
 
-       spin_lock_init(&line6pcm->out.lock);
-       spin_lock_init(&line6pcm->in.lock);
-       line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
-
-       line6->line6pcm = line6pcm;
-
-       pcm->private_data = line6pcm;
-       pcm->private_free = line6_cleanup_pcm;
-
        err = line6_create_audio_out_urbs(line6pcm);
        if (err < 0)
                return err;
index 7498b51..eceab19 100644 (file)
@@ -68,6 +68,7 @@ struct mixer_build {
        unsigned char *buffer;
        unsigned int buflen;
        DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
+       DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
        struct usb_audio_term oterm;
        const struct usbmix_name_map *map;
        const struct usbmix_selector_map *selector_map;
@@ -738,12 +739,13 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
                                       struct uac_mixer_unit_descriptor *desc)
 {
        int mu_channels;
-       void *c;
 
        if (desc->bLength < sizeof(*desc))
                return -EINVAL;
        if (!desc->bNrInPins)
                return -EINVAL;
+       if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
+               return -EINVAL;
 
        switch (state->mixer->protocol) {
        case UAC_VERSION_1:
@@ -759,13 +761,6 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
                break;
        }
 
-       if (!mu_channels)
-               return 0;
-
-       c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
-       if (c - (void *)desc + (mu_channels - 1) / 8 >= desc->bLength)
-               return 0; /* no bmControls -> skip */
-
        return mu_channels;
 }
 
@@ -773,16 +768,25 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
  * parse the source unit recursively until it reaches to a terminal
  * or a branched unit.
  */
-static int check_input_term(struct mixer_build *state, int id,
+static int __check_input_term(struct mixer_build *state, int id,
                            struct usb_audio_term *term)
 {
        int protocol = state->mixer->protocol;
        int err;
        void *p1;
+       unsigned char *hdr;
 
        memset(term, 0, sizeof(*term));
-       while ((p1 = find_audio_control_unit(state, id)) != NULL) {
-               unsigned char *hdr = p1;
+       for (;;) {
+               /* a loop in the terminal chain? */
+               if (test_and_set_bit(id, state->termbitmap))
+                       return -EINVAL;
+
+               p1 = find_audio_control_unit(state, id);
+               if (!p1)
+                       break;
+
+               hdr = p1;
                term->id = id;
 
                if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
@@ -800,7 +804,7 @@ static int check_input_term(struct mixer_build *state, int id,
 
                                        /* call recursively to verify that the
                                         * referenced clock entity is valid */
-                                       err = check_input_term(state, d->bCSourceID, term);
+                                       err = __check_input_term(state, d->bCSourceID, term);
                                        if (err < 0)
                                                return err;
 
@@ -834,7 +838,7 @@ static int check_input_term(struct mixer_build *state, int id,
                        case UAC2_CLOCK_SELECTOR: {
                                struct uac_selector_unit_descriptor *d = p1;
                                /* call recursively to retrieve the channel info */
-                               err = check_input_term(state, d->baSourceID[0], term);
+                               err = __check_input_term(state, d->baSourceID[0], term);
                                if (err < 0)
                                        return err;
                                term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
@@ -897,7 +901,7 @@ static int check_input_term(struct mixer_build *state, int id,
 
                                /* call recursively to verify that the
                                 * referenced clock entity is valid */
-                               err = check_input_term(state, d->bCSourceID, term);
+                               err = __check_input_term(state, d->bCSourceID, term);
                                if (err < 0)
                                        return err;
 
@@ -948,7 +952,7 @@ static int check_input_term(struct mixer_build *state, int id,
                        case UAC3_CLOCK_SELECTOR: {
                                struct uac_selector_unit_descriptor *d = p1;
                                /* call recursively to retrieve the channel info */
-                               err = check_input_term(state, d->baSourceID[0], term);
+                               err = __check_input_term(state, d->baSourceID[0], term);
                                if (err < 0)
                                        return err;
                                term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
@@ -964,7 +968,7 @@ static int check_input_term(struct mixer_build *state, int id,
                                        return -EINVAL;
 
                                /* call recursively to retrieve the channel info */
-                               err = check_input_term(state, d->baSourceID[0], term);
+                               err = __check_input_term(state, d->baSourceID[0], term);
                                if (err < 0)
                                        return err;
 
@@ -982,6 +986,15 @@ static int check_input_term(struct mixer_build *state, int id,
        return -ENODEV;
 }
 
+
+static int check_input_term(struct mixer_build *state, int id,
+                           struct usb_audio_term *term)
+{
+       memset(term, 0, sizeof(*term));
+       memset(state->termbitmap, 0, sizeof(state->termbitmap));
+       return __check_input_term(state, id, term);
+}
+
 /*
  * Feature Unit
  */
@@ -1988,6 +2001,31 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
  * Mixer Unit
  */
 
+/* check whether the given in/out overflows bmMixerControls matrix */
+static bool mixer_bitmap_overflow(struct uac_mixer_unit_descriptor *desc,
+                                 int protocol, int num_ins, int num_outs)
+{
+       u8 *hdr = (u8 *)desc;
+       u8 *c = uac_mixer_unit_bmControls(desc, protocol);
+       size_t rest; /* remaining bytes after bmMixerControls */
+
+       switch (protocol) {
+       case UAC_VERSION_1:
+       default:
+               rest = 1; /* iMixer */
+               break;
+       case UAC_VERSION_2:
+               rest = 2; /* bmControls + iMixer */
+               break;
+       case UAC_VERSION_3:
+               rest = 6; /* bmControls + wMixerDescrStr */
+               break;
+       }
+
+       /* overflow? */
+       return c + (num_ins * num_outs + 7) / 8 + rest > hdr + hdr[0];
+}
+
 /*
  * build a mixer unit control
  *
@@ -2116,6 +2154,9 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
                if (err < 0)
                        return err;
                num_ins += iterm.channels;
+               if (mixer_bitmap_overflow(desc, state->mixer->protocol,
+                                         num_ins, num_outs))
+                       break;
                for (; ich < num_ins; ich++) {
                        int och, ich_has_controls = 0;
 
index 199fa15..27dcb37 100644 (file)
@@ -1155,17 +1155,17 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
 {
        struct usb_mixer_interface *mixer;
        struct usb_mixer_elem_info *cval;
-       int unitid = 12; /* SamleRate ExtensionUnit ID */
+       int unitid = 12; /* SampleRate ExtensionUnit ID */
 
        list_for_each_entry(mixer, &chip->mixer_list, list) {
-               cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
-               if (cval) {
+               if (mixer->id_elems[unitid]) {
+                       cval = mixer_elem_list_to_info(mixer->id_elems[unitid]);
                        snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
                                                    cval->control << 8,
                                                    samplerate_id);
                        snd_usb_mixer_notify_id(mixer, unitid);
+                       break;
                }
-               break;
        }
 }
 
index 75b9692..e4bbf79 100644 (file)
@@ -339,6 +339,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
                ep = 0x81;
                ifnum = 2;
                goto add_sync_ep_from_ifnum;
+       case USB_ID(0x1397, 0x0001): /* Behringer UFX1604 */
        case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */
                ep = 0x81;
                ifnum = 1;
diff --git a/tools/arch/riscv/include/uapi/asm/perf_regs.h b/tools/arch/riscv/include/uapi/asm/perf_regs.h
new file mode 100644 (file)
index 0000000..196f964
--- /dev/null
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#ifndef _ASM_RISCV_PERF_REGS_H
+#define _ASM_RISCV_PERF_REGS_H
+
+enum perf_event_riscv_regs {
+       PERF_REG_RISCV_PC,
+       PERF_REG_RISCV_RA,
+       PERF_REG_RISCV_SP,
+       PERF_REG_RISCV_GP,
+       PERF_REG_RISCV_TP,
+       PERF_REG_RISCV_T0,
+       PERF_REG_RISCV_T1,
+       PERF_REG_RISCV_T2,
+       PERF_REG_RISCV_S0,
+       PERF_REG_RISCV_S1,
+       PERF_REG_RISCV_A0,
+       PERF_REG_RISCV_A1,
+       PERF_REG_RISCV_A2,
+       PERF_REG_RISCV_A3,
+       PERF_REG_RISCV_A4,
+       PERF_REG_RISCV_A5,
+       PERF_REG_RISCV_A6,
+       PERF_REG_RISCV_A7,
+       PERF_REG_RISCV_S2,
+       PERF_REG_RISCV_S3,
+       PERF_REG_RISCV_S4,
+       PERF_REG_RISCV_S5,
+       PERF_REG_RISCV_S6,
+       PERF_REG_RISCV_S7,
+       PERF_REG_RISCV_S8,
+       PERF_REG_RISCV_S9,
+       PERF_REG_RISCV_S10,
+       PERF_REG_RISCV_S11,
+       PERF_REG_RISCV_T3,
+       PERF_REG_RISCV_T4,
+       PERF_REG_RISCV_T5,
+       PERF_REG_RISCV_T6,
+       PERF_REG_RISCV_MAX,
+};
+#endif /* _ASM_RISCV_PERF_REGS_H */
index 5215e08..6a71324 100644 (file)
@@ -204,7 +204,11 @@ int do_pin_fd(int fd, const char *name)
        if (err)
                return err;
 
-       return bpf_obj_pin(fd, name);
+       err = bpf_obj_pin(fd, name);
+       if (err)
+               p_err("can't pin the object (%s): %s", name, strerror(errno));
+
+       return err;
 }
 
 int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
@@ -237,7 +241,7 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
 
        fd = get_fd_by_id(id);
        if (fd < 0) {
-               p_err("can't get prog by id (%u): %s", id, strerror(errno));
+               p_err("can't open object by id (%u): %s", id, strerror(errno));
                return -1;
        }
 
index 66f04a4..43fdbbf 100644 (file)
@@ -363,7 +363,9 @@ static int do_show(int argc, char **argv)
                if (fd < 0)
                        return -1;
 
-               return show_prog(fd);
+               err = show_prog(fd);
+               close(fd);
+               return err;
        }
 
        if (argc)
index c38686c..2f2a3c7 100755 (executable)
@@ -13,7 +13,7 @@
 #      the script prints the string "Disabled" to stdout.
 #
 # Each Distro is expected to implement this script in a distro specific
-# fashion. For instance on Distros that ship with Network Manager enabled,
+# fashion. For instance, on Distros that ship with Network Manager enabled,
 # this script can be based on the Network Manager APIs for retrieving DHCP
 # information.
 
index d7e06fe..e9ef4ca 100644 (file)
@@ -700,7 +700,7 @@ static void kvp_get_ipconfig_info(char *if_name,
 
 
        /*
-        * Gather the DNS  state.
+        * Gather the DNS state.
         * Since there is no standard way to get this information
         * across various distributions of interest; we just invoke
         * an external script that needs to be ported across distros
@@ -809,7 +809,7 @@ kvp_get_ip_info(int family, char *if_name, int op,
        int sn_offset = 0;
        int error = 0;
        char *buffer;
-       struct hv_kvp_ipaddr_value *ip_buffer;
+       struct hv_kvp_ipaddr_value *ip_buffer = NULL;
        char cidr_mask[5]; /* /xyz */
        int weight;
        int i;
@@ -1051,7 +1051,7 @@ static int parse_ip_val_buffer(char *in_buf, int *offset,
        char *start;
 
        /*
-        * in_buf has sequence of characters that are seperated by
+        * in_buf has sequence of characters that are separated by
         * the character ';'. The last sequence does not have the
         * terminating ";" character.
         */
@@ -1386,6 +1386,8 @@ int main(int argc, char *argv[])
                        daemonize = 0;
                        break;
                case 'h':
+                       print_usage(argv);
+                       exit(0);
                default:
                        print_usage(argv);
                        exit(EXIT_FAILURE);
@@ -1490,7 +1492,7 @@ int main(int argc, char *argv[])
                case KVP_OP_GET_IP_INFO:
                        kvp_ip_val = &hv_msg->body.kvp_ip_val;
 
-                       error =  kvp_mac_to_ip(kvp_ip_val);
+                       error = kvp_mac_to_ip(kvp_ip_val);
 
                        if (error)
                                hv_msg->error = error;
index 7ed9f85..d10fe35 100755 (executable)
@@ -12,7 +12,7 @@
 # be used to configure the interface.
 #
 # Each Distro is expected to implement this script in a distro specific
-# fashion. For instance on Distros that ship with Network Manager enabled,
+# fashion. For instance, on Distros that ship with Network Manager enabled,
 # this script can be based on the Network Manager APIs for configuring the
 # interface.
 #
index efe1e34..92902a8 100644 (file)
@@ -42,7 +42,7 @@ static int vss_do_freeze(char *dir, unsigned int cmd)
         * If a partition is mounted more than once, only the first
         * FREEZE/THAW can succeed and the later ones will get
         * EBUSY/EINVAL respectively: there could be 2 cases:
-        * 1) a user may mount the same partition to differnt directories
+        * 1) a user may mount the same partition to different directories
         *  by mistake or on purpose;
         * 2) The subvolume of btrfs appears to have the same partition
         * mounted more than once.
@@ -218,6 +218,8 @@ int main(int argc, char *argv[])
                        daemonize = 0;
                        break;
                case 'h':
+                       print_usage(argv);
+                       exit(0);
                default:
                        print_usage(argv);
                        exit(EXIT_FAILURE);
index 55e7374..099f2c4 100644 (file)
@@ -4,10 +4,10 @@
 import os
 from optparse import OptionParser
 
+help_msg = "print verbose messages. Try -vv, -vvv for  more verbose messages"
 parser = OptionParser()
-parser.add_option("-v", "--verbose", dest="verbose",
-                  help="print verbose messages. Try -vv, -vvv for \
-                       more verbose messages", action="count")
+parser.add_option(
+       "-v", "--verbose", dest="verbose", help=help_msg, action="count")
 
 (options, args) = parser.parse_args()
 
@@ -21,27 +21,28 @@ if not os.path.isdir(vmbus_sys_path):
        exit(-1)
 
 vmbus_dev_dict = {
-       '{0e0b6031-5213-4934-818b-38d90ced39db}' : '[Operating system shutdown]',
-       '{9527e630-d0ae-497b-adce-e80ab0175caf}' : '[Time Synchronization]',
-       '{57164f39-9115-4e78-ab55-382f3bd5422d}' : '[Heartbeat]',
-       '{a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}' : '[Data Exchange]',
-       '{35fa2e29-ea23-4236-96ae-3a6ebacba440}' : '[Backup (volume checkpoint)]',
-       '{34d14be3-dee4-41c8-9ae7-6b174977c192}' : '[Guest services]',
-       '{525074dc-8985-46e2-8057-a307dc18a502}' : '[Dynamic Memory]',
-       '{cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}' : 'Synthetic mouse',
-       '{f912ad6d-2b17-48ea-bd65-f927a61c7684}' : 'Synthetic keyboard',
-       '{da0a7802-e377-4aac-8e77-0558eb1073f8}' : 'Synthetic framebuffer adapter',
-       '{f8615163-df3e-46c5-913f-f2d2f965ed0e}' : 'Synthetic network adapter',
-       '{32412632-86cb-44a2-9b5c-50d1417354f5}' : 'Synthetic IDE Controller',
-       '{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}' : 'Synthetic SCSI Controller',
-       '{2f9bcc4a-0069-4af3-b76b-6fd0be528cda}' : 'Synthetic fiber channel adapter',
-       '{8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}' : 'Synthetic RDMA adapter',
-       '{44c4f61d-4444-4400-9d52-802e27ede19f}' : 'PCI Express pass-through',
-       '{276aacf4-ac15-426c-98dd-7521ad3f01fe}' : '[Reserved system device]',
-       '{f8e65716-3cb3-4a06-9a60-1889c5cccab5}' : '[Reserved system device]',
-       '{3375baf4-9e15-4b30-b765-67acb10d607b}' : '[Reserved system device]',
+       '{0e0b6031-5213-4934-818b-38d90ced39db}': '[Operating system shutdown]',
+       '{9527e630-d0ae-497b-adce-e80ab0175caf}': '[Time Synchronization]',
+       '{57164f39-9115-4e78-ab55-382f3bd5422d}': '[Heartbeat]',
+       '{a9a0f4e7-5a45-4d96-b827-8a841e8c03e6}': '[Data Exchange]',
+       '{35fa2e29-ea23-4236-96ae-3a6ebacba440}': '[Backup (volume checkpoint)]',
+       '{34d14be3-dee4-41c8-9ae7-6b174977c192}': '[Guest services]',
+       '{525074dc-8985-46e2-8057-a307dc18a502}': '[Dynamic Memory]',
+       '{cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a}': 'Synthetic mouse',
+       '{f912ad6d-2b17-48ea-bd65-f927a61c7684}': 'Synthetic keyboard',
+       '{da0a7802-e377-4aac-8e77-0558eb1073f8}': 'Synthetic framebuffer adapter',
+       '{f8615163-df3e-46c5-913f-f2d2f965ed0e}': 'Synthetic network adapter',
+       '{32412632-86cb-44a2-9b5c-50d1417354f5}': 'Synthetic IDE Controller',
+       '{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}': 'Synthetic SCSI Controller',
+       '{2f9bcc4a-0069-4af3-b76b-6fd0be528cda}': 'Synthetic fiber channel adapter',
+       '{8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}': 'Synthetic RDMA adapter',
+       '{44c4f61d-4444-4400-9d52-802e27ede19f}': 'PCI Express pass-through',
+       '{276aacf4-ac15-426c-98dd-7521ad3f01fe}': '[Reserved system device]',
+       '{f8e65716-3cb3-4a06-9a60-1889c5cccab5}': '[Reserved system device]',
+       '{3375baf4-9e15-4b30-b765-67acb10d607b}': '[Reserved system device]',
 }
 
+
 def get_vmbus_dev_attr(dev_name, attr):
        try:
                f = open('%s/%s/%s' % (vmbus_sys_path, dev_name, attr), 'r')
@@ -52,6 +53,7 @@ def get_vmbus_dev_attr(dev_name, attr):
 
        return lines
 
+
 class VMBus_Dev:
        pass
 
@@ -66,12 +68,13 @@ for f in os.listdir(vmbus_sys_path):
 
        chn_vp_mapping = get_vmbus_dev_attr(f, 'channel_vp_mapping')
        chn_vp_mapping = [c.strip() for c in chn_vp_mapping]
-       chn_vp_mapping = sorted(chn_vp_mapping,
-               key = lambda c : int(c.split(':')[0]))
+       chn_vp_mapping = sorted(
+               chn_vp_mapping, key=lambda c: int(c.split(':')[0]))
 
-       chn_vp_mapping = ['\tRel_ID=%s, target_cpu=%s' %
-                               (c.split(':')[0], c.split(':')[1])
-                                       for c in chn_vp_mapping]
+       chn_vp_mapping = [
+               '\tRel_ID=%s, target_cpu=%s' %
+               (c.split(':')[0], c.split(':')[1]) for c in chn_vp_mapping
+       ]
        d = VMBus_Dev()
        d.sysfs_path = '%s/%s' % (vmbus_sys_path, f)
        d.vmbus_id = vmbus_id
@@ -85,7 +88,7 @@ for f in os.listdir(vmbus_sys_path):
        vmbus_dev_list.append(d)
 
 
-vmbus_dev_list  = sorted(vmbus_dev_list, key = lambda d : int(d.vmbus_id))
+vmbus_dev_list = sorted(vmbus_dev_list, key=lambda d: int(d.vmbus_id))
 
 format0 = '%2s: %s'
 format1 = '%2s: Class_ID = %s - %s\n%s'
@@ -95,9 +98,15 @@ for d in vmbus_dev_list:
        if verbose == 0:
                print(('VMBUS ID ' + format0) % (d.vmbus_id, d.dev_desc))
        elif verbose == 1:
-               print (('VMBUS ID ' + format1) %        \
-                       (d.vmbus_id, d.class_id, d.dev_desc, d.chn_vp_mapping))
+               print(
+                       ('VMBUS ID ' + format1) %
+                       (d.vmbus_id, d.class_id, d.dev_desc, d.chn_vp_mapping)
+               )
        else:
-               print (('VMBUS ID ' + format2) % \
-                       (d.vmbus_id, d.class_id, d.dev_desc, \
-                       d.device_id, d.sysfs_path, d.chn_vp_mapping))
+               print(
+                       ('VMBUS ID ' + format2) %
+                       (
+                               d.vmbus_id, d.class_id, d.dev_desc,
+                               d.device_id, d.sysfs_path, d.chn_vp_mapping
+                       )
+               )
index 4e45501..a5aa7d3 100644 (file)
@@ -1466,8 +1466,8 @@ union bpf_attr {
  *             If no cookie has been set yet, generate a new cookie. Once
  *             generated, the socket cookie remains stable for the life of the
  *             socket. This helper can be useful for monitoring per socket
- *             networking traffic statistics as it provides a unique socket
- *             identifier per namespace.
+ *             networking traffic statistics as it provides a global socket
+ *             identifier that can be assumed unique.
  *     Return
  *             A 8-byte long non-decreasing number on success, or 0 if the
  *             socket field is missing inside *skb*.
@@ -1571,8 +1571,11 @@ union bpf_attr {
  *             but this is only implemented for native XDP (with driver
  *             support) as of this writing).
  *
- *             All values for *flags* are reserved for future usage, and must
- *             be left at zero.
+ *             The lower two bits of *flags* are used as the return code if
+ *             the map lookup fails. This is so that the return value can be
+ *             one of the XDP program return codes up to XDP_TX, as chosen by
+ *             the caller. Any higher bits in the *flags* argument must be
+ *             unset.
  *
  *             When used to redirect packets to net devices, this helper
  *             provides a high performance increase over **bpf_redirect**\ ().
index 2586b6c..2b57d7e 100644 (file)
@@ -182,7 +182,6 @@ struct bpf_program {
        bpf_program_clear_priv_t clear_priv;
 
        enum bpf_attach_type expected_attach_type;
-       int btf_fd;
        void *func_info;
        __u32 func_info_rec_size;
        __u32 func_info_cnt;
@@ -313,7 +312,6 @@ void bpf_program__unload(struct bpf_program *prog)
        prog->instances.nr = -1;
        zfree(&prog->instances.fds);
 
-       zclose(prog->btf_fd);
        zfree(&prog->func_info);
        zfree(&prog->line_info);
 }
@@ -392,7 +390,6 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
        prog->instances.fds = NULL;
        prog->instances.nr = -1;
        prog->type = BPF_PROG_TYPE_UNSPEC;
-       prog->btf_fd = -1;
 
        return 0;
 errout:
@@ -2288,9 +2285,6 @@ bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
                prog->line_info_rec_size = btf_ext__line_info_rec_size(obj->btf_ext);
        }
 
-       if (!insn_offset)
-               prog->btf_fd = btf__fd(obj->btf);
-
        return 0;
 }
 
@@ -2463,7 +2457,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
        char *cp, errmsg[STRERR_BUFSIZE];
        int log_buf_size = BPF_LOG_BUF_SIZE;
        char *log_buf;
-       int ret;
+       int btf_fd, ret;
 
        if (!insns || !insns_cnt)
                return -EINVAL;
@@ -2478,7 +2472,12 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
        load_attr.license = license;
        load_attr.kern_version = kern_version;
        load_attr.prog_ifindex = prog->prog_ifindex;
-       load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
+       /* if .BTF.ext was loaded, kernel supports associated BTF for prog */
+       if (prog->obj->btf_ext)
+               btf_fd = bpf_object__btf_fd(prog->obj);
+       else
+               btf_fd = -1;
+       load_attr.prog_btf_fd = btf_fd >= 0 ? btf_fd : 0;
        load_attr.func_info = prog->func_info;
        load_attr.func_info_rec_size = prog->func_info_rec_size;
        load_attr.func_info_cnt = prog->func_info_cnt;
@@ -5000,13 +4999,15 @@ int libbpf_num_possible_cpus(void)
        static const char *fcpu = "/sys/devices/system/cpu/possible";
        int len = 0, n = 0, il = 0, ir = 0;
        unsigned int start = 0, end = 0;
+       int tmp_cpus = 0;
        static int cpus;
        char buf[128];
        int error = 0;
        int fd = -1;
 
-       if (cpus > 0)
-               return cpus;
+       tmp_cpus = READ_ONCE(cpus);
+       if (tmp_cpus > 0)
+               return tmp_cpus;
 
        fd = open(fcpu, O_RDONLY);
        if (fd < 0) {
@@ -5029,7 +5030,7 @@ int libbpf_num_possible_cpus(void)
        }
        buf[len] = '\0';
 
-       for (ir = 0, cpus = 0; ir <= len; ir++) {
+       for (ir = 0, tmp_cpus = 0; ir <= len; ir++) {
                /* Each sub string separated by ',' has format \d+-\d+ or \d+ */
                if (buf[ir] == ',' || buf[ir] == '\0') {
                        buf[ir] = '\0';
@@ -5041,13 +5042,15 @@ int libbpf_num_possible_cpus(void)
                        } else if (n == 1) {
                                end = start;
                        }
-                       cpus += end - start + 1;
+                       tmp_cpus += end - start + 1;
                        il = ir + 1;
                }
        }
-       if (cpus <= 0) {
-               pr_warning("Invalid #CPUs %d from %s\n", cpus, fcpu);
+       if (tmp_cpus <= 0) {
+               pr_warning("Invalid #CPUs %d from %s\n", tmp_cpus, fcpu);
                return -EINVAL;
        }
-       return cpus;
+
+       WRITE_ONCE(cpus, tmp_cpus);
+       return tmp_cpus;
 }
index 89ac5a1..eaf25ee 100644 (file)
@@ -60,6 +60,10 @@ ifeq ($(SRCARCH),arm64)
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(SRCARCH),riscv)
+  NO_PERF_REGS := 0
+endif
+
 ifeq ($(SRCARCH),csky)
   NO_PERF_REGS := 0
 endif
@@ -82,7 +86,7 @@ endif
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
diff --git a/tools/perf/arch/riscv/Build b/tools/perf/arch/riscv/Build
new file mode 100644 (file)
index 0000000..e4e5f33
--- /dev/null
@@ -0,0 +1 @@
+perf-y += util/
diff --git a/tools/perf/arch/riscv/Makefile b/tools/perf/arch/riscv/Makefile
new file mode 100644 (file)
index 0000000..1aa9dd7
--- /dev/null
@@ -0,0 +1,4 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+endif
+PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
new file mode 100644 (file)
index 0000000..7a8bcde
--- /dev/null
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <asm/perf_regs.h>
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
+#define PERF_REGS_MAX  PERF_REG_RISCV_MAX
+#if __riscv_xlen == 64
+#define PERF_SAMPLE_REGS_ABI    PERF_SAMPLE_REGS_ABI_64
+#else
+#define PERF_SAMPLE_REGS_ABI   PERF_SAMPLE_REGS_ABI_32
+#endif
+
+#define PERF_REG_IP    PERF_REG_RISCV_PC
+#define PERF_REG_SP    PERF_REG_RISCV_SP
+
+static inline const char *perf_reg_name(int id)
+{
+       switch (id) {
+       case PERF_REG_RISCV_PC:
+               return "pc";
+       case PERF_REG_RISCV_RA:
+               return "ra";
+       case PERF_REG_RISCV_SP:
+               return "sp";
+       case PERF_REG_RISCV_GP:
+               return "gp";
+       case PERF_REG_RISCV_TP:
+               return "tp";
+       case PERF_REG_RISCV_T0:
+               return "t0";
+       case PERF_REG_RISCV_T1:
+               return "t1";
+       case PERF_REG_RISCV_T2:
+               return "t2";
+       case PERF_REG_RISCV_S0:
+               return "s0";
+       case PERF_REG_RISCV_S1:
+               return "s1";
+       case PERF_REG_RISCV_A0:
+               return "a0";
+       case PERF_REG_RISCV_A1:
+               return "a1";
+       case PERF_REG_RISCV_A2:
+               return "a2";
+       case PERF_REG_RISCV_A3:
+               return "a3";
+       case PERF_REG_RISCV_A4:
+               return "a4";
+       case PERF_REG_RISCV_A5:
+               return "a5";
+       case PERF_REG_RISCV_A6:
+               return "a6";
+       case PERF_REG_RISCV_A7:
+               return "a7";
+       case PERF_REG_RISCV_S2:
+               return "s2";
+       case PERF_REG_RISCV_S3:
+               return "s3";
+       case PERF_REG_RISCV_S4:
+               return "s4";
+       case PERF_REG_RISCV_S5:
+               return "s5";
+       case PERF_REG_RISCV_S6:
+               return "s6";
+       case PERF_REG_RISCV_S7:
+               return "s7";
+       case PERF_REG_RISCV_S8:
+               return "s8";
+       case PERF_REG_RISCV_S9:
+               return "s9";
+       case PERF_REG_RISCV_S10:
+               return "s10";
+       case PERF_REG_RISCV_S11:
+               return "s11";
+       case PERF_REG_RISCV_T3:
+               return "t3";
+       case PERF_REG_RISCV_T4:
+               return "t4";
+       case PERF_REG_RISCV_T5:
+               return "t5";
+       case PERF_REG_RISCV_T6:
+               return "t6";
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
new file mode 100644 (file)
index 0000000..1160bb2
--- /dev/null
@@ -0,0 +1,2 @@
+perf-$(CONFIG_DWARF) += dwarf-regs.o
+perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/riscv/util/dwarf-regs.c b/tools/perf/arch/riscv/util/dwarf-regs.c
new file mode 100644 (file)
index 0000000..cd0504c
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+ * Mapping of DWARF debug register numbers into register names.
+ */
+
+#include <stddef.h>
+#include <errno.h> /* for EINVAL */
+#include <string.h> /* for strcmp */
+#include <dwarf-regs.h>
+
+struct pt_regs_dwarfnum {
+       const char *name;
+       unsigned int dwarfnum;
+};
+
+#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
+#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
+
+struct pt_regs_dwarfnum riscv_dwarf_regs_table[] = {
+       REG_DWARFNUM_NAME("%zero", 0),
+       REG_DWARFNUM_NAME("%ra", 1),
+       REG_DWARFNUM_NAME("%sp", 2),
+       REG_DWARFNUM_NAME("%gp", 3),
+       REG_DWARFNUM_NAME("%tp", 4),
+       REG_DWARFNUM_NAME("%t0", 5),
+       REG_DWARFNUM_NAME("%t1", 6),
+       REG_DWARFNUM_NAME("%t2", 7),
+       REG_DWARFNUM_NAME("%s0", 8),
+       REG_DWARFNUM_NAME("%s1", 9),
+       REG_DWARFNUM_NAME("%a0", 10),
+       REG_DWARFNUM_NAME("%a1", 11),
+       REG_DWARFNUM_NAME("%a2", 12),
+       REG_DWARFNUM_NAME("%a3", 13),
+       REG_DWARFNUM_NAME("%a4", 14),
+       REG_DWARFNUM_NAME("%a5", 15),
+       REG_DWARFNUM_NAME("%a6", 16),
+       REG_DWARFNUM_NAME("%a7", 17),
+       REG_DWARFNUM_NAME("%s2", 18),
+       REG_DWARFNUM_NAME("%s3", 19),
+       REG_DWARFNUM_NAME("%s4", 20),
+       REG_DWARFNUM_NAME("%s5", 21),
+       REG_DWARFNUM_NAME("%s6", 22),
+       REG_DWARFNUM_NAME("%s7", 23),
+       REG_DWARFNUM_NAME("%s8", 24),
+       REG_DWARFNUM_NAME("%s9", 25),
+       REG_DWARFNUM_NAME("%s10", 26),
+       REG_DWARFNUM_NAME("%s11", 27),
+       REG_DWARFNUM_NAME("%t3", 28),
+       REG_DWARFNUM_NAME("%t4", 29),
+       REG_DWARFNUM_NAME("%t5", 30),
+       REG_DWARFNUM_NAME("%t6", 31),
+       REG_DWARFNUM_END,
+};
+
+#define RISCV_MAX_REGS ((sizeof(riscv_dwarf_regs_table) / \
+                sizeof(riscv_dwarf_regs_table[0])) - 1)
+
+const char *get_arch_regstr(unsigned int n)
+{
+       return (n < RISCV_MAX_REGS) ? riscv_dwarf_regs_table[n].name : NULL;
+}
+
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_dwarfnum *roff;
+
+       for (roff = riscv_dwarf_regs_table; roff->name; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->dwarfnum;
+       return -EINVAL;
+}
diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/arch/riscv/util/unwind-libdw.c
new file mode 100644 (file)
index 0000000..19536e1
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
+
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+#include "../../util/event.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct regs_dump *user_regs = &ui->sample->user_regs;
+       Dwarf_Word dwarf_regs[32];
+
+#define REG(r) ({                                              \
+       Dwarf_Word val = 0;                                     \
+       perf_reg_value(&val, user_regs, PERF_REG_RISCV_##r);    \
+       val;                                                    \
+})
+
+       dwarf_regs[0]  = 0;
+       dwarf_regs[1]  = REG(RA);
+       dwarf_regs[2]  = REG(SP);
+       dwarf_regs[3]  = REG(GP);
+       dwarf_regs[4]  = REG(TP);
+       dwarf_regs[5]  = REG(T0);
+       dwarf_regs[6]  = REG(T1);
+       dwarf_regs[7]  = REG(T2);
+       dwarf_regs[8]  = REG(S0);
+       dwarf_regs[9]  = REG(S1);
+       dwarf_regs[10] = REG(A0);
+       dwarf_regs[11] = REG(A1);
+       dwarf_regs[12] = REG(A2);
+       dwarf_regs[13] = REG(A3);
+       dwarf_regs[14] = REG(A4);
+       dwarf_regs[15] = REG(A5);
+       dwarf_regs[16] = REG(A6);
+       dwarf_regs[17] = REG(A7);
+       dwarf_regs[18] = REG(S2);
+       dwarf_regs[19] = REG(S3);
+       dwarf_regs[20] = REG(S4);
+       dwarf_regs[21] = REG(S5);
+       dwarf_regs[22] = REG(S6);
+       dwarf_regs[23] = REG(S7);
+       dwarf_regs[24] = REG(S8);
+       dwarf_regs[25] = REG(S9);
+       dwarf_regs[26] = REG(S10);
+       dwarf_regs[27] = REG(S11);
+       dwarf_regs[28] = REG(T3);
+       dwarf_regs[29] = REG(T4);
+       dwarf_regs[30] = REG(T5);
+       dwarf_regs[31] = REG(T6);
+       dwfl_thread_state_register_pc(thread, REG(PC));
+
+       return dwfl_thread_state_registers(thread, 0, PERF_REG_RISCV_MAX,
+                                          dwarf_regs);
+}
index 045f5f7..13f1e8b 100644 (file)
@@ -9,9 +9,10 @@ ifeq ("$(origin O)", "command line")
 endif
 
 turbostat : turbostat.c
-override CFLAGS +=     -Wall -I../../../include
+override CFLAGS +=     -O2 -Wall -I../../../include
 override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
 override CFLAGS +=     -DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
+override CFLAGS +=     -D_FORTIFY_SOURCE=2
 
 %: %.c
        @mkdir -p $(BUILD_OUTPUT)
index 75fc4fb..b2a8643 100644 (file)
@@ -39,7 +39,6 @@ FILE *outf;
 int *fd_percpu;
 struct timeval interval_tv = {5, 0};
 struct timespec interval_ts = {5, 0};
-struct timespec one_msec = {0, 1000000};
 unsigned int num_iterations;
 unsigned int debug;
 unsigned int quiet;
@@ -60,6 +59,7 @@ unsigned int do_irtl_hsw;
 unsigned int units = 1000000;  /* MHz etc */
 unsigned int genuine_intel;
 unsigned int authentic_amd;
+unsigned int hygon_genuine;
 unsigned int max_level, max_extended_level;
 unsigned int has_invariant_tsc;
 unsigned int do_nhm_platform_info;
@@ -100,6 +100,7 @@ unsigned int has_hwp_epp;           /* IA32_HWP_REQUEST[bits 31:24] */
 unsigned int has_hwp_pkg;              /* IA32_HWP_REQUEST_PKG */
 unsigned int has_misc_feature_control;
 unsigned int first_counter_read = 1;
+int ignore_stdin;
 
 #define RAPL_PKG               (1 << 0)
                                        /* 0x610 MSR_PKG_POWER_LIMIT */
@@ -166,6 +167,7 @@ size_t cpu_present_setsize, cpu_affinity_setsize, cpu_subset_size;
 struct thread_data {
        struct timeval tv_begin;
        struct timeval tv_end;
+       struct timeval tv_delta;
        unsigned long long tsc;
        unsigned long long aperf;
        unsigned long long mperf;
@@ -506,6 +508,7 @@ unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAU
 unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC;
 
 #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME)
+#define DO_BIC_READ(COUNTER_NAME) (bic_present & COUNTER_NAME)
 #define ENABLE_BIC(COUNTER_NAME) (bic_enabled |= COUNTER_NAME)
 #define BIC_PRESENT(COUNTER_BIT) (bic_present |= COUNTER_BIT)
 #define BIC_NOT_PRESENT(COUNTER_BIT) (bic_present &= ~COUNTER_BIT)
@@ -849,7 +852,6 @@ int dump_counters(struct thread_data *t, struct core_data *c,
                outp += sprintf(outp, "pc8: %016llX\n", p->pc8);
                outp += sprintf(outp, "pc9: %016llX\n", p->pc9);
                outp += sprintf(outp, "pc10: %016llX\n", p->pc10);
-               outp += sprintf(outp, "pc10: %016llX\n", p->pc10);
                outp += sprintf(outp, "cpu_lpi: %016llX\n", p->cpu_lpi);
                outp += sprintf(outp, "sys_lpi: %016llX\n", p->sys_lpi);
                outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg);
@@ -911,7 +913,7 @@ int format_counters(struct thread_data *t, struct core_data *c,
        if (DO_BIC(BIC_TOD))
                outp += sprintf(outp, "%10ld.%06ld\t", t->tv_end.tv_sec, t->tv_end.tv_usec);
 
-       interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
+       interval_float = t->tv_delta.tv_sec + t->tv_delta.tv_usec/1000000.0;
 
        tsc = t->tsc * tsc_tweak;
 
@@ -1287,6 +1289,14 @@ delta_core(struct core_data *new, struct core_data *old)
        }
 }
 
+int soft_c1_residency_display(int bic)
+{
+       if (!DO_BIC(BIC_CPU_c1) || use_c1_residency_msr)
+               return 0;
+
+       return DO_BIC_READ(bic);
+}
+
 /*
  * old = new - old
  */
@@ -1309,6 +1319,7 @@ delta_thread(struct thread_data *new, struct thread_data *old,
         * over-write old w/ new so we can print end of interval values
         */
 
+       timersub(&new->tv_begin, &old->tv_begin, &old->tv_delta);
        old->tv_begin = new->tv_begin;
        old->tv_end = new->tv_end;
 
@@ -1322,7 +1333,8 @@ delta_thread(struct thread_data *new, struct thread_data *old,
 
        old->c1 = new->c1 - old->c1;
 
-       if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
+       if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) ||
+           soft_c1_residency_display(BIC_Avg_MHz)) {
                if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
                        old->aperf = new->aperf - old->aperf;
                        old->mperf = new->mperf - old->mperf;
@@ -1404,6 +1416,8 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
        t->tv_begin.tv_usec = 0;
        t->tv_end.tv_sec = 0;
        t->tv_end.tv_usec = 0;
+       t->tv_delta.tv_sec = 0;
+       t->tv_delta.tv_usec = 0;
 
        t->tsc = 0;
        t->aperf = 0;
@@ -1573,6 +1587,9 @@ void compute_average(struct thread_data *t, struct core_data *c,
 
        for_all_cpus(sum_counters, t, c, p);
 
+       /* Use the global time delta for the average. */
+       average.threads.tv_delta = tv_delta;
+
        average.threads.tsc /= topo.num_cpus;
        average.threads.aperf /= topo.num_cpus;
        average.threads.mperf /= topo.num_cpus;
@@ -1714,7 +1731,7 @@ void get_apic_id(struct thread_data *t)
        if (!DO_BIC(BIC_X2APIC))
                return;
 
-       if (authentic_amd) {
+       if (authentic_amd || hygon_genuine) {
                unsigned int topology_extensions;
 
                if (max_extended_level < 0x8000001e)
@@ -1762,19 +1779,20 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        struct msr_counter *mp;
        int i;
 
-       gettimeofday(&t->tv_begin, (struct timezone *)NULL);
-
        if (cpu_migrate(cpu)) {
                fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
+       gettimeofday(&t->tv_begin, (struct timezone *)NULL);
+
        if (first_counter_read)
                get_apic_id(t);
 retry:
        t->tsc = rdtsc();       /* we are running on local CPU of interest */
 
-       if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
+       if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) ||
+           soft_c1_residency_display(BIC_Avg_MHz)) {
                unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
 
                /*
@@ -1851,20 +1869,20 @@ retry:
        if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
                goto done;
 
-       if (DO_BIC(BIC_CPU_c3)) {
+       if (DO_BIC(BIC_CPU_c3) || soft_c1_residency_display(BIC_CPU_c3)) {
                if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
                        return -6;
        }
 
-       if (DO_BIC(BIC_CPU_c6) && !do_knl_cstates) {
+       if ((DO_BIC(BIC_CPU_c6) || soft_c1_residency_display(BIC_CPU_c6)) && !do_knl_cstates) {
                if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
                        return -7;
-       } else if (do_knl_cstates) {
+       } else if (do_knl_cstates || soft_c1_residency_display(BIC_CPU_c6)) {
                if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6))
                        return -7;
        }
 
-       if (DO_BIC(BIC_CPU_c7))
+       if (DO_BIC(BIC_CPU_c7) || soft_c1_residency_display(BIC_CPU_c7))
                if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
                        return -8;
 
@@ -2912,6 +2930,7 @@ int snapshot_cpu_lpi_us(void)
        if (retval != 1) {
                fprintf(stderr, "Disabling Low Power Idle CPU output\n");
                BIC_NOT_PRESENT(BIC_CPU_LPI);
+               fclose(fp);
                return -1;
        }
 
@@ -2938,6 +2957,7 @@ int snapshot_sys_lpi_us(void)
        if (retval != 1) {
                fprintf(stderr, "Disabling Low Power Idle System output\n");
                BIC_NOT_PRESENT(BIC_SYS_LPI);
+               fclose(fp);
                return -1;
        }
        fclose(fp);
@@ -2985,8 +3005,6 @@ static void signal_handler (int signal)
                        fprintf(stderr, "SIGUSR1\n");
                break;
        }
-       /* make sure this manually-invoked interval is at least 1ms long */
-       nanosleep(&one_msec, NULL);
 }
 
 void setup_signal_handler(void)
@@ -3005,29 +3023,38 @@ void setup_signal_handler(void)
 
 void do_sleep(void)
 {
-       struct timeval select_timeout;
+       struct timeval tout;
+       struct timespec rest;
        fd_set readfds;
        int retval;
 
        FD_ZERO(&readfds);
        FD_SET(0, &readfds);
 
-       if (!isatty(fileno(stdin))) {
+       if (ignore_stdin) {
                nanosleep(&interval_ts, NULL);
                return;
        }
 
-       select_timeout = interval_tv;
-       retval = select(1, &readfds, NULL, NULL, &select_timeout);
+       tout = interval_tv;
+       retval = select(1, &readfds, NULL, NULL, &tout);
 
        if (retval == 1) {
                switch (getc(stdin)) {
                case 'q':
                        exit_requested = 1;
                        break;
+               case EOF:
+                       /*
+                        * 'stdin' is a pipe closed on the other end. There
+                        * won't be any further input.
+                        */
+                       ignore_stdin = 1;
+                       /* Sleep the rest of the time */
+                       rest.tv_sec = (tout.tv_sec + tout.tv_usec / 1000000);
+                       rest.tv_nsec = (tout.tv_usec % 1000000) * 1000;
+                       nanosleep(&rest, NULL);
                }
-               /* make sure this manually-invoked interval is at least 1ms long */
-               nanosleep(&one_msec, NULL);
        }
 }
 
@@ -3209,6 +3236,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
                break;
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSX */
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
@@ -3405,6 +3433,7 @@ int has_config_tdp(unsigned int family, unsigned int model)
        case INTEL_FAM6_IVYBRIDGE:      /* IVB */
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSX */
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
@@ -3803,6 +3832,7 @@ double get_tdp_amd(unsigned int family)
 {
        switch (family) {
        case 0x17:
+       case 0x18:
        default:
                /* This is the max stock TDP of HEDT/Server Fam17h chips */
                return 250.0;
@@ -3841,6 +3871,7 @@ void rapl_probe_intel(unsigned int family, unsigned int model)
        case INTEL_FAM6_SANDYBRIDGE:
        case INTEL_FAM6_IVYBRIDGE:
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
@@ -3982,6 +4013,7 @@ void rapl_probe_amd(unsigned int family, unsigned int model)
 
        switch (family) {
        case 0x17: /* Zen, Zen+ */
+       case 0x18: /* Hygon Dhyana */
                do_rapl = RAPL_AMD_F17H | RAPL_PER_CORE_ENERGY;
                if (rapl_joules) {
                        BIC_PRESENT(BIC_Pkg_J);
@@ -4002,7 +4034,7 @@ void rapl_probe_amd(unsigned int family, unsigned int model)
        rapl_energy_units = ldexp(1.0, -(msr >> 8 & 0x1f));
        rapl_power_units = ldexp(1.0, -(msr & 0xf));
 
-       tdp = get_tdp_amd(model);
+       tdp = get_tdp_amd(family);
 
        rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
        if (!quiet)
@@ -4018,7 +4050,7 @@ void rapl_probe(unsigned int family, unsigned int model)
 {
        if (genuine_intel)
                rapl_probe_intel(family, model);
-       if (authentic_amd)
+       if (authentic_amd || hygon_genuine)
                rapl_probe_amd(family, model);
 }
 
@@ -4032,6 +4064,7 @@ void perf_limit_reasons_probe(unsigned int family, unsigned int model)
 
        switch (model) {
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
                do_gfx_perf_limit_reasons = 1;
        case INTEL_FAM6_HASWELL_X:      /* HSX */
@@ -4251,6 +4284,7 @@ int has_snb_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_IVYBRIDGE_X:    /* IVB Xeon */
        case INTEL_FAM6_HASWELL_CORE:   /* HSW */
        case INTEL_FAM6_HASWELL_X:      /* HSW */
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_HASWELL_GT3E:   /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_BROADWELL_GT3E: /* BDW */
@@ -4267,7 +4301,7 @@ int has_snb_msrs(unsigned int family, unsigned int model)
 }
 
 /*
- * HSW adds support for additional MSRs:
+ * HSW ULT added support for C8/C9/C10 MSRs:
  *
  * MSR_PKG_C8_RESIDENCY                0x00000630
  * MSR_PKG_C9_RESIDENCY                0x00000631
@@ -4278,13 +4312,13 @@ int has_snb_msrs(unsigned int family, unsigned int model)
  * MSR_PKGC10_IRTL             0x00000635
  *
  */
-int has_hsw_msrs(unsigned int family, unsigned int model)
+int has_c8910_msrs(unsigned int family, unsigned int model)
 {
        if (!genuine_intel)
                return 0;
 
        switch (model) {
-       case INTEL_FAM6_HASWELL_CORE:
+       case INTEL_FAM6_HASWELL_ULT:    /* HSW */
        case INTEL_FAM6_BROADWELL_CORE: /* BDW */
        case INTEL_FAM6_SKYLAKE_MOBILE: /* SKL */
        case INTEL_FAM6_CANNONLAKE_MOBILE:      /* CNL */
@@ -4568,9 +4602,6 @@ unsigned int intel_model_duplicates(unsigned int model)
        case INTEL_FAM6_XEON_PHI_KNM:
                return INTEL_FAM6_XEON_PHI_KNL;
 
-       case INTEL_FAM6_HASWELL_ULT:
-               return INTEL_FAM6_HASWELL_CORE;
-
        case INTEL_FAM6_BROADWELL_X:
        case INTEL_FAM6_BROADWELL_XEON_D:       /* BDX-DE */
                return INTEL_FAM6_BROADWELL_X;
@@ -4582,7 +4613,11 @@ unsigned int intel_model_duplicates(unsigned int model)
                return INTEL_FAM6_SKYLAKE_MOBILE;
 
        case INTEL_FAM6_ICELAKE_MOBILE:
+       case INTEL_FAM6_ICELAKE_NNPI:
                return INTEL_FAM6_CANNONLAKE_MOBILE;
+
+       case INTEL_FAM6_ATOM_TREMONT_X:
+               return INTEL_FAM6_ATOM_GOLDMONT_X;
        }
        return model;
 }
@@ -4600,6 +4635,8 @@ void process_cpuid()
                genuine_intel = 1;
        else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
                authentic_amd = 1;
+       else if (ebx == 0x6f677948 && ecx == 0x656e6975 && edx == 0x6e65476e)
+               hygon_genuine = 1;
 
        if (!quiet)
                fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
@@ -4820,12 +4857,12 @@ void process_cpuid()
                BIC_NOT_PRESENT(BIC_CPU_c7);
                BIC_NOT_PRESENT(BIC_Pkgpc7);
        }
-       if (has_hsw_msrs(family, model)) {
+       if (has_c8910_msrs(family, model)) {
                BIC_PRESENT(BIC_Pkgpc8);
                BIC_PRESENT(BIC_Pkgpc9);
                BIC_PRESENT(BIC_Pkgpc10);
        }
-       do_irtl_hsw = has_hsw_msrs(family, model);
+       do_irtl_hsw = has_c8910_msrs(family, model);
        if (has_skl_msrs(family, model)) {
                BIC_PRESENT(BIC_Totl_c0);
                BIC_PRESENT(BIC_Any_c0);
@@ -5123,7 +5160,7 @@ int initialize_counters(int cpu_id)
 
 void allocate_output_buffer()
 {
-       output_buffer = calloc(1, (1 + topo.num_cpus) * 1024);
+       output_buffer = calloc(1, (1 + topo.num_cpus) * 2048);
        outp = output_buffer;
        if (outp == NULL)
                err(-1, "calloc output buffer");
@@ -5269,7 +5306,7 @@ int get_and_dump_counters(void)
 }
 
 void print_version() {
-       fprintf(outf, "turbostat version 19.03.20"
+       fprintf(outf, "turbostat version 19.08.31"
                " - Len Brown <lenb@kernel.org>\n");
 }
 
index 1fdeef8..666b325 100644 (file)
@@ -9,8 +9,9 @@ ifeq ("$(origin O)", "command line")
 endif
 
 x86_energy_perf_policy : x86_energy_perf_policy.c
-override CFLAGS +=     -Wall -I../../../include
+override CFLAGS +=     -O2 -Wall -I../../../include
 override CFLAGS +=     -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=     -D_FORTIFY_SOURCE=2
 
 %: %.c
        @mkdir -p $(BUILD_OUTPUT)
index 17db1c3..78c6361 100644 (file)
@@ -40,7 +40,7 @@ in the same processor package.
 Hardware P-States (HWP) are effectively an expansion of hardware
 P-state control from the opportunistic turbo-mode P-state range
 to include the entire range of available P-states.
-On Broadwell Xeon, the initial HWP implementation, EBP influenced HWP.
+On Broadwell Xeon, the initial HWP implementation, EPB influenced HWP.
 That influence was removed in subsequent generations,
 where it was moved to the
 Energy_Performance_Preference (EPP) field in
index 34a796b..3fe1eed 100644 (file)
@@ -545,7 +545,7 @@ void cmdline(int argc, char **argv)
 
        progname = argv[0];
 
-       while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw",
+       while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw:",
                                long_options, &option_index)) != -1) {
                switch (opt) {
                case 'a':
@@ -1259,6 +1259,15 @@ void probe_dev_msr(void)
                if (system("/sbin/modprobe msr > /dev/null 2>&1"))
                        err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
 }
+
+static void get_cpuid_or_exit(unsigned int leaf,
+                            unsigned int *eax, unsigned int *ebx,
+                            unsigned int *ecx, unsigned int *edx)
+{
+       if (!__get_cpuid(leaf, eax, ebx, ecx, edx))
+               errx(1, "Processor not supported\n");
+}
+
 /*
  * early_cpuid()
  * initialize turbo_is_enabled, has_hwp, has_epb
@@ -1266,15 +1275,10 @@ void probe_dev_msr(void)
  */
 void early_cpuid(void)
 {
-       unsigned int eax, ebx, ecx, edx, max_level;
+       unsigned int eax, ebx, ecx, edx;
        unsigned int fms, family, model;
 
-       __get_cpuid(0, &max_level, &ebx, &ecx, &edx);
-
-       if (max_level < 6)
-               errx(1, "Processor not supported\n");
-
-       __get_cpuid(1, &fms, &ebx, &ecx, &edx);
+       get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
        family = (fms >> 8) & 0xf;
        model = (fms >> 4) & 0xf;
        if (family == 6 || family == 0xf)
@@ -1288,7 +1292,7 @@ void early_cpuid(void)
                bdx_highest_ratio = msr & 0xFF;
        }
 
-       __get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
+       get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
        turbo_is_enabled = (eax >> 1) & 1;
        has_hwp = (eax >> 7) & 1;
        has_epb = (ecx >> 3) & 1;
@@ -1306,7 +1310,7 @@ void parse_cpuid(void)
 
        eax = ebx = ecx = edx = 0;
 
-       __get_cpuid(0, &max_level, &ebx, &ecx, &edx);
+       get_cpuid_or_exit(0, &max_level, &ebx, &ecx, &edx);
 
        if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
                genuine_intel = 1;
@@ -1315,7 +1319,7 @@ void parse_cpuid(void)
                fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
                        (char *)&ebx, (char *)&edx, (char *)&ecx);
 
-       __get_cpuid(1, &fms, &ebx, &ecx, &edx);
+       get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
        family = (fms >> 8) & 0xf;
        model = (fms >> 4) & 0xf;
        stepping = fms & 0xf;
@@ -1340,7 +1344,7 @@ void parse_cpuid(void)
                errx(1, "CPUID: no MSR");
 
 
-       __get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
+       get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
        /* turbo_is_enabled already set */
        /* has_hwp already set */
        has_hwp_notify = eax & (1 << 8);
diff --git a/tools/testing/selftests/arm64/.gitignore b/tools/testing/selftests/arm64/.gitignore
new file mode 100644 (file)
index 0000000..e8fae8d
--- /dev/null
@@ -0,0 +1 @@
+tags_test
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
new file mode 100644 (file)
index 0000000..a61b2e7
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# ARCH can be overridden by the user for cross compiling
+ARCH ?= $(shell uname -m 2>/dev/null || echo not)
+
+ifneq (,$(filter $(ARCH),aarch64 arm64))
+TEST_GEN_PROGS := tags_test
+TEST_PROGS := run_tags_test.sh
+endif
+
+include ../lib.mk
diff --git a/tools/testing/selftests/arm64/run_tags_test.sh b/tools/testing/selftests/arm64/run_tags_test.sh
new file mode 100755 (executable)
index 0000000..745f113
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+echo "--------------------"
+echo "running tags test"
+echo "--------------------"
+./tags_test
+if [ $? -ne 0 ]; then
+       echo "[FAIL]"
+else
+       echo "[PASS]"
+fi
diff --git a/tools/testing/selftests/arm64/tags_test.c b/tools/testing/selftests/arm64/tags_test.c
new file mode 100644 (file)
index 0000000..5701163
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <sys/utsname.h>
+
+#define SHIFT_TAG(tag)         ((uint64_t)(tag) << 56)
+#define SET_TAG(ptr, tag)      (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \
+                                       SHIFT_TAG(tag))
+
+int main(void)
+{
+       static int tbi_enabled = 0;
+       unsigned long tag = 0;
+       struct utsname *ptr;
+       int err;
+
+       if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0)
+               tbi_enabled = 1;
+       ptr = (struct utsname *)malloc(sizeof(*ptr));
+       if (tbi_enabled)
+               tag = 0x42;
+       ptr = (struct utsname *)SET_TAG(ptr, tag);
+       err = uname(ptr);
+       free(ptr);
+
+       return err;
+}
index c085964..96752eb 100644 (file)
@@ -34,6 +34,9 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
 BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c)))
 TEST_GEN_FILES = $(BPF_OBJ_FILES)
 
+BTF_C_FILES = $(wildcard progs/btf_dump_test_case_*.c)
+TEST_FILES = $(BTF_C_FILES)
+
 # Also test sub-register code-gen if LLVM has eBPF v3 processor support which
 # contains both ALU32 and JMP32 instructions.
 SUBREG_CODEGEN := $(shell echo "int cal(int a) { return a > 0; }" | \
@@ -68,7 +71,8 @@ TEST_PROGS := test_kmod.sh \
 TEST_PROGS_EXTENDED := with_addr.sh \
        with_tunnels.sh \
        tcp_client.py \
-       tcp_server.py
+       tcp_server.py \
+       test_xdp_vlan.sh
 
 # Compile but not part of 'make run_tests'
 TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \
index f7a0744..5dc109f 100644 (file)
@@ -34,3 +34,4 @@ CONFIG_NET_MPLS_GSO=m
 CONFIG_MPLS_ROUTING=m
 CONFIG_MPLS_IPTUNNEL=m
 CONFIG_IPV6_SIT=m
+CONFIG_BPF_JIT=y
index 8f85082..6e75dd3 100644 (file)
@@ -97,6 +97,13 @@ int test_btf_dump_case(int n, struct btf_dump_test_case *test_case)
        }
 
        snprintf(test_file, sizeof(test_file), "progs/%s.c", test_case->name);
+       if (access(test_file, R_OK) == -1)
+               /*
+                * When the test is run with O=, kselftest copies TEST_FILES
+                * without preserving the directory structure.
+                */
+               snprintf(test_file, sizeof(test_file), "%s.c",
+                       test_case->name);
        /*
         * Diff test output and expected test output, contained between
         * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case.
index 2fc4625..6557290 100644 (file)
@@ -20,9 +20,9 @@ int main(int argc, char **argv)
                BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
                BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
                             BPF_FUNC_get_local_storage),
-               BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0),
                BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1),
-               BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0),
+               BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0),
 
                BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */
                BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
@@ -30,7 +30,7 @@ int main(int argc, char **argv)
                             BPF_FUNC_get_local_storage),
                BPF_MOV64_IMM(BPF_REG_1, 1),
                BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
-               BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
                BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1),
                BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
                BPF_EXIT_INSN(),
index fb679ac..0e66527 100644 (file)
@@ -13,6 +13,7 @@
 #include <bpf/bpf.h>
 
 #include "cgroup_helpers.h"
+#include "bpf_endian.h"
 #include "bpf_rlimit.h"
 #include "bpf_util.h"
 
@@ -232,7 +233,8 @@ static struct sock_test tests[] = {
                        /* if (ip == expected && port == expected) */
                        BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
                                    offsetof(struct bpf_sock, src_ip6[3])),
-                       BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x01000000, 4),
+                       BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
+                                   __bpf_constant_ntohl(0x00000001), 4),
                        BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
                                    offsetof(struct bpf_sock, src_port)),
                        BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2),
@@ -261,7 +263,8 @@ static struct sock_test tests[] = {
                        /* if (ip == expected && port == expected) */
                        BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
                                    offsetof(struct bpf_sock, src_ip4)),
-                       BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x0100007F, 4),
+                       BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
+                                   __bpf_constant_ntohl(0x7F000001), 4),
                        BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
                                    offsetof(struct bpf_sock, src_port)),
                        BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2),
index 5e980a5..1fc4e61 100644 (file)
        .errstr = "loop detected",
        .prog_type = BPF_PROG_TYPE_TRACEPOINT,
 },
+{
+       "not-taken loop with back jump to 1st insn",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 123),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 4, -2),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .retval = 123,
+},
+{
+       "taken loop with back jump to 1st insn",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_1, 10),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1),
+       BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, -3),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .retval = 55,
+},
index 8219a30..0fc1b6d 100644 (file)
@@ -447,6 +447,59 @@ cleanup:
        return ret;
 }
 
+/*
+ * The test creates a cgroups and freezes it. Then it creates a child cgroup
+ * and populates it with a task. After that it checks that the child cgroup
+ * is frozen and the parent cgroup remains frozen too.
+ */
+static int test_cgfreezer_mkdir(const char *root)
+{
+       int ret = KSFT_FAIL;
+       char *parent, *child = NULL;
+       int pid;
+
+       parent = cg_name(root, "cg_test_mkdir_A");
+       if (!parent)
+               goto cleanup;
+
+       child = cg_name(parent, "cg_test_mkdir_B");
+       if (!child)
+               goto cleanup;
+
+       if (cg_create(parent))
+               goto cleanup;
+
+       if (cg_freeze_wait(parent, true))
+               goto cleanup;
+
+       if (cg_create(child))
+               goto cleanup;
+
+       pid = cg_run_nowait(child, child_fn, NULL);
+       if (pid < 0)
+               goto cleanup;
+
+       if (cg_wait_for_proc_count(child, 1))
+               goto cleanup;
+
+       if (cg_check_frozen(child, true))
+               goto cleanup;
+
+       if (cg_check_frozen(parent, true))
+               goto cleanup;
+
+       ret = KSFT_PASS;
+
+cleanup:
+       if (child)
+               cg_destroy(child);
+       free(child);
+       if (parent)
+               cg_destroy(parent);
+       free(parent);
+       return ret;
+}
+
 /*
  * The test creates two nested cgroups, freezes the parent
  * and removes the child. Then it checks that the parent cgroup
@@ -815,6 +868,7 @@ struct cgfreezer_test {
        T(test_cgfreezer_simple),
        T(test_cgfreezer_tree),
        T(test_cgfreezer_forkbomb),
+       T(test_cgfreezer_mkdir),
        T(test_cgfreezer_rmdir),
        T(test_cgfreezer_migrate),
        T(test_cgfreezer_ptrace),
index 4059014..4912d23 100644 (file)
@@ -220,6 +220,8 @@ struct hv_enlightened_vmcs {
 struct hv_enlightened_vmcs *current_evmcs;
 struct hv_vp_assist_page *current_vp_assist;
 
+int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id);
+
 static inline int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist)
 {
        u64 val = (vp_assist_pa & HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK) |
index 6cb34a0..0a5e487 100644 (file)
@@ -1060,9 +1060,11 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
         TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XSAVE, r: %i",
                 r);
 
-       r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs);
-        TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i",
-                r);
+       if (kvm_check_cap(KVM_CAP_XCRS)) {
+               r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs);
+               TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i",
+                           r);
+       }
 
        r = ioctl(vcpu->fd, KVM_GET_SREGS, &state->sregs);
         TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_SREGS, r: %i",
@@ -1103,9 +1105,11 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s
         TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XSAVE, r: %i",
                 r);
 
-       r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs);
-        TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i",
-                r);
+       if (kvm_check_cap(KVM_CAP_XCRS)) {
+               r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs);
+               TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i",
+                           r);
+       }
 
        r = ioctl(vcpu->fd, KVM_SET_SREGS, &state->sregs);
         TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_SREGS, r: %i",
index 204f847..9cef045 100644 (file)
 
 bool enable_evmcs;
 
+int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id)
+{
+       uint16_t evmcs_ver;
+
+       struct kvm_enable_cap enable_evmcs_cap = {
+               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
+                .args[0] = (unsigned long)&evmcs_ver
+       };
+
+       vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_evmcs_cap);
+
+       /* KVM should return supported EVMCS version range */
+       TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) &&
+                   (evmcs_ver & 0xff) > 0,
+                   "Incorrect EVMCS version range: %x:%x\n",
+                   evmcs_ver & 0xff, evmcs_ver >> 8);
+
+       return evmcs_ver;
+}
+
 /* Allocate memory regions for nested VMX tests.
  *
  * Input Args:
index f95c083..92915e6 100644 (file)
@@ -79,11 +79,6 @@ int main(int argc, char *argv[])
        struct kvm_x86_state *state;
        struct ucall uc;
        int stage;
-       uint16_t evmcs_ver;
-       struct kvm_enable_cap enable_evmcs_cap = {
-               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
-                .args[0] = (unsigned long)&evmcs_ver
-       };
 
        /* Create VM */
        vm = vm_create_default(VCPU_ID, 0, guest_code);
@@ -96,13 +91,7 @@ int main(int argc, char *argv[])
                exit(KSFT_SKIP);
        }
 
-       vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
-
-       /* KVM should return supported EVMCS version range */
-       TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) &&
-                   (evmcs_ver & 0xff) > 0,
-                   "Incorrect EVMCS version range: %x:%x\n",
-                   evmcs_ver & 0xff, evmcs_ver >> 8);
+       vcpu_enable_evmcs(vm, VCPU_ID);
 
        run = vcpu_state(vm, VCPU_ID);
 
@@ -146,7 +135,7 @@ int main(int argc, char *argv[])
                kvm_vm_restart(vm, O_RDWR);
                vm_vcpu_add(vm, VCPU_ID);
                vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
-               vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
+               vcpu_enable_evmcs(vm, VCPU_ID);
                vcpu_load_state(vm, VCPU_ID, state);
                run = vcpu_state(vm, VCPU_ID);
                free(state);
index f72b304..ee59831 100644 (file)
@@ -18,6 +18,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "vmx.h"
 
 #define VCPU_ID 0
 
@@ -106,12 +107,7 @@ int main(int argc, char *argv[])
 {
        struct kvm_vm *vm;
        int rv;
-       uint16_t evmcs_ver;
        struct kvm_cpuid2 *hv_cpuid_entries;
-       struct kvm_enable_cap enable_evmcs_cap = {
-               .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS,
-                .args[0] = (unsigned long)&evmcs_ver
-       };
 
        /* Tell stdout not to buffer its content */
        setbuf(stdout, NULL);
@@ -136,14 +132,14 @@ int main(int argc, char *argv[])
 
        free(hv_cpuid_entries);
 
-       rv = _vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap);
-
-       if (rv) {
+       if (!kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) {
                fprintf(stderr,
                        "Enlightened VMCS is unsupported, skip related test\n");
                goto vm_free;
        }
 
+       vcpu_enable_evmcs(vm, VCPU_ID);
+
        hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm);
        if (!hv_cpuid_entries)
                return 1;
index 40050e4..f9334bd 100644 (file)
@@ -99,8 +99,8 @@ int main(int argc, char *argv[])
        msr_platform_info = vcpu_get_msr(vm, VCPU_ID, MSR_PLATFORM_INFO);
        vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO,
                msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO);
-       test_msr_platform_info_disabled(vm);
        test_msr_platform_info_enabled(vm);
+       test_msr_platform_info_disabled(vm);
        vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info);
 
        kvm_vm_free(vm);
index ed7218d..853e370 100644 (file)
 #define VMCS12_REVISION 0x11e57ed0
 #define VCPU_ID 5
 
+bool have_evmcs;
+
 void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state)
 {
-       volatile struct kvm_run *run;
-
        vcpu_nested_state_set(vm, VCPU_ID, state, false);
-       run = vcpu_state(vm, VCPU_ID);
-       vcpu_run(vm, VCPU_ID);
-       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
-               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
-               run->exit_reason,
-               exit_reason_str(run->exit_reason));
 }
 
 void test_nested_state_expect_errno(struct kvm_vm *vm,
                                    struct kvm_nested_state *state,
                                    int expected_errno)
 {
-       volatile struct kvm_run *run;
        int rv;
 
        rv = vcpu_nested_state_set(vm, VCPU_ID, state, true);
@@ -50,12 +43,6 @@ void test_nested_state_expect_errno(struct kvm_vm *vm,
                "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)",
                strerror(expected_errno), expected_errno, rv, strerror(errno),
                errno);
-       run = vcpu_state(vm, VCPU_ID);
-       vcpu_run(vm, VCPU_ID);
-       TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN,
-               "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n",
-               run->exit_reason,
-               exit_reason_str(run->exit_reason));
 }
 
 void test_nested_state_expect_einval(struct kvm_vm *vm,
@@ -90,8 +77,9 @@ void set_default_vmx_state(struct kvm_nested_state *state, int size)
 {
        memset(state, 0, size);
        state->flags = KVM_STATE_NESTED_GUEST_MODE  |
-                       KVM_STATE_NESTED_RUN_PENDING |
-                       KVM_STATE_NESTED_EVMCS;
+                       KVM_STATE_NESTED_RUN_PENDING;
+       if (have_evmcs)
+               state->flags |= KVM_STATE_NESTED_EVMCS;
        state->format = 0;
        state->size = size;
        state->hdr.vmx.vmxon_pa = 0x1000;
@@ -141,13 +129,19 @@ void test_vmx_nested_state(struct kvm_vm *vm)
        /*
         * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
         * setting the nested state but flags other than eVMCS must be clear.
+        * The eVMCS flag can be set if the enlightened VMCS capability has
+        * been enabled.
         */
        set_default_vmx_state(state, state_sz);
        state->hdr.vmx.vmxon_pa = -1ull;
        state->hdr.vmx.vmcs12_pa = -1ull;
        test_nested_state_expect_einval(vm, state);
 
-       state->flags = KVM_STATE_NESTED_EVMCS;
+       state->flags &= KVM_STATE_NESTED_EVMCS;
+       if (have_evmcs) {
+               test_nested_state_expect_einval(vm, state);
+               vcpu_enable_evmcs(vm, VCPU_ID);
+       }
        test_nested_state(vm, state);
 
        /* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
@@ -232,6 +226,8 @@ int main(int argc, char *argv[])
        struct kvm_nested_state state;
        struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
 
+       have_evmcs = kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS);
+
        if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) {
                printf("KVM_CAP_NESTED_STATE not available, skipping test\n");
                exit(KSFT_SKIP);
index c5c93d5..f9ebeac 100755 (executable)
@@ -212,6 +212,8 @@ check_output()
                        printf "        ${out}\n"
                        printf "    Expected:\n"
                        printf "        ${expected}\n\n"
+               else
+                       echo "      WARNING: Unexpected route entry"
                fi
        fi
 
@@ -274,7 +276,7 @@ ipv6_fcnal()
 
        run_cmd "$IP nexthop get id 52"
        log_test $? 0 "Get nexthop by id"
-       check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1"
+       check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1 scope link"
 
        run_cmd "$IP nexthop del id 52"
        log_test $? 0 "Delete nexthop by id"
@@ -479,12 +481,12 @@ ipv6_fcnal_runtime()
        run_cmd "$IP -6 nexthop add id 85 dev veth1"
        run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 85"
        log_test $? 0 "IPv6 route with device only nexthop"
-       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1"
+       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1 metric 1024 pref medium"
 
        run_cmd "$IP nexthop add id 123 group 81/85"
        run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 123"
        log_test $? 0 "IPv6 multipath route with nexthop mix - dev only + gw"
-       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 nexthop via 2001:db8:91::2 dev veth1 nexthop dev veth1"
+       check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 123 metric 1024 nexthop via 2001:db8:91::2 dev veth1 weight 1 nexthop dev veth1 weight 1 pref medium"
 
        #
        # IPv6 route with v4 nexthop - not allowed
@@ -538,7 +540,7 @@ ipv4_fcnal()
 
        run_cmd "$IP nexthop get id 12"
        log_test $? 0 "Get nexthop by id"
-       check_nexthop "id 12" "id 12 via 172.16.1.2 src 172.16.1.1 dev veth1 scope link"
+       check_nexthop "id 12" "id 12 via 172.16.1.2 dev veth1 scope link"
 
        run_cmd "$IP nexthop del id 12"
        log_test $? 0 "Delete nexthop by id"
@@ -685,7 +687,7 @@ ipv4_withv6_fcnal()
        set +e
        run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
-       check_route "172.16.101.1" "172.16.101.1 nhid 11 via ${lladdr} dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 11 via inet6 ${lladdr} dev veth1"
 
        set -e
        run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
@@ -694,11 +696,11 @@ ipv4_withv6_fcnal()
        run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
 
-       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
 
        run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
        log_test $? 0 "IPv4 route with IPv6 gateway"
-       check_route "172.16.101.1" "172.16.101.1 via ${lladdr} dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 via inet6 ${lladdr} dev veth1"
 
        run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
        log_test $? 2 "IPv4 route with invalid IPv6 gateway"
@@ -785,10 +787,10 @@ ipv4_fcnal_runtime()
        log_test $? 0 "IPv4 route with device only nexthop"
        check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
 
-       run_cmd "$IP nexthop add id 122 group 21/85"
-       run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
+       run_cmd "$IP nexthop add id 123 group 21/85"
+       run_cmd "$IP ro replace 172.16.101.1/32 nhid 123"
        log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
-       check_route "172.16.101.1" "172.16.101.1 nhid 85 nexthop via 172.16.1.2 dev veth1 nexthop dev veth1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 123 nexthop via 172.16.1.2 dev veth1 weight 1 nexthop dev veth1 weight 1"
 
        #
        # IPv4 with IPv6
@@ -820,7 +822,7 @@ ipv4_fcnal_runtime()
        run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
        log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
 
-       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
+       check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
 
        run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
        log_test $? 0 "IPv6 nexthop with IPv4 route"
index 4147639..f6e6567 100755 (executable)
@@ -30,7 +30,7 @@ do_test() {
        ip netns exec "${NETNS}" ./tcp_fastopen_backup_key "$1"
        val=$(ip netns exec "${NETNS}" nstat -az | \
                grep TcpExtTCPFastOpenPassiveFail | awk '{print $2}')
-       if [ $val -ne 0 ]; then
+       if [ "$val" != 0 ]; then
                echo "FAIL: TcpExtTCPFastOpenPassiveFail non-zero"
                return 1
        fi
index 5445943..7a1bf94 100755 (executable)
@@ -106,6 +106,13 @@ do_overlap()
     #
     # 10.0.0.0/24 and 10.0.1.0/24 nodes have been merged as 10.0.0.0/23.
     ip -net $ns xfrm policy add src 10.1.0.0/24 dst 10.0.0.0/23 dir fwd priority 200 action block
+
+    # similar to above: add policies (with partially random address), with shrinking prefixes.
+    for p in 29 28 27;do
+      for k in $(seq 1 32); do
+       ip -net $ns xfrm policy add src 10.253.1.$((RANDOM%255))/$p dst 10.254.1.$((RANDOM%255))/$p dir fwd priority $((200+k)) action block 2>/dev/null
+      done
+    done
 }
 
 do_esp_policy_get_check() {
index fe52488..16571ac 100755 (executable)
@@ -321,4 +321,52 @@ else
        ip netns exec nsr1 nft list ruleset
 fi
 
+KEY_SHA="0x"$(ps -xaf | sha1sum | cut -d " " -f 1)
+KEY_AES="0x"$(ps -xaf | md5sum | cut -d " " -f 1)
+SPI1=$RANDOM
+SPI2=$RANDOM
+
+if [ $SPI1 -eq $SPI2 ]; then
+       SPI2=$((SPI2+1))
+fi
+
+do_esp() {
+    local ns=$1
+    local me=$2
+    local remote=$3
+    local lnet=$4
+    local rnet=$5
+    local spi_out=$6
+    local spi_in=$7
+
+    ip -net $ns xfrm state add src $remote dst $me proto esp spi $spi_in  enc aes $KEY_AES  auth sha1 $KEY_SHA mode tunnel sel src $rnet dst $lnet
+    ip -net $ns xfrm state add src $me  dst $remote proto esp spi $spi_out enc aes $KEY_AES auth sha1 $KEY_SHA mode tunnel sel src $lnet dst $rnet
+
+    # to encrypt packets as they go out (includes forwarded packets that need encapsulation)
+    ip -net $ns xfrm policy add src $lnet dst $rnet dir out tmpl src $me dst $remote proto esp mode tunnel priority 1 action allow
+    # to fwd decrypted packets after esp processing:
+    ip -net $ns xfrm policy add src $rnet dst $lnet dir fwd tmpl src $remote dst $me proto esp mode tunnel priority 1 action allow
+
+}
+
+do_esp nsr1 192.168.10.1 192.168.10.2 10.0.1.0/24 10.0.2.0/24 $SPI1 $SPI2
+
+do_esp nsr2 192.168.10.2 192.168.10.1 10.0.2.0/24 10.0.1.0/24 $SPI2 $SPI1
+
+ip netns exec nsr1 nft delete table ip nat
+
+# restore default routes
+ip -net ns2 route del 192.168.10.1 via 10.0.2.1
+ip -net ns2 route add default via 10.0.2.1
+ip -net ns2 route add default via dead:2::1
+
+test_tcp_forwarding ns1 ns2
+if [ $? -eq 0 ] ;then
+       echo "PASS: ipsec tunnel mode for ns1/ns2"
+else
+       echo "FAIL: ipsec tunnel mode for ns1/ns2"
+       ip netns exec nsr1 nft list ruleset 1>&2
+       ip netns exec nsr1 cat /proc/net/xfrm_stat 1>&2
+fi
+
 exit $ret
index 720b2d8..464c9b7 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 CFLAGS += -g -I../../../../usr/include/ -lpthread
 
-TEST_GEN_PROGS := pidfd_test pidfd_open_test
+TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_poll_test pidfd_wait
 
 include ../lib.mk
 
index 8452e91..c6bc683 100644 (file)
 
 #include "../kselftest.h"
 
+#ifndef P_PIDFD
+#define P_PIDFD 3
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000
+#endif
+
+#ifndef __NR_pidfd_open
+#define __NR_pidfd_open -1
+#endif
+
+#ifndef __NR_pidfd_send_signal
+#define __NR_pidfd_send_signal -1
+#endif
+
+#ifndef __NR_clone3
+#define __NR_clone3 -1
+#endif
+
 /*
  * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
  * That means, when it wraps around any pid < 300 will be skipped.
@@ -53,5 +73,15 @@ again:
        return WEXITSTATUS(status);
 }
 
+static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
+{
+       return syscall(__NR_pidfd_open, pid, flags);
+}
+
+static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
+                                       unsigned int flags)
+{
+       return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
+}
 
 #endif /* __PIDFD_H */
index 0377133..b9fe75f 100644 (file)
 #include "pidfd.h"
 #include "../kselftest.h"
 
-static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
-{
-       return syscall(__NR_pidfd_open, pid, flags);
-}
-
 static int safe_int(const char *numstr, int *converted)
 {
        char *err = NULL;
diff --git a/tools/testing/selftests/pidfd/pidfd_poll_test.c b/tools/testing/selftests/pidfd/pidfd_poll_test.c
new file mode 100644 (file)
index 0000000..4b11544
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "pidfd.h"
+#include "../kselftest.h"
+
+static bool timeout;
+
+static void handle_alarm(int sig)
+{
+       timeout = true;
+}
+
+int main(int argc, char **argv)
+{
+       struct pollfd fds;
+       int iter, nevents;
+       int nr_iterations = 10000;
+
+       fds.events = POLLIN;
+
+       if (argc > 2)
+               ksft_exit_fail_msg("Unexpected command line argument\n");
+
+       if (argc == 2) {
+               nr_iterations = atoi(argv[1]);
+               if (nr_iterations <= 0)
+                       ksft_exit_fail_msg("invalid input parameter %s\n",
+                                       argv[1]);
+       }
+
+       ksft_print_msg("running pidfd poll test for %d iterations\n",
+               nr_iterations);
+
+       for (iter = 0; iter < nr_iterations; iter++) {
+               int pidfd;
+               int child_pid = fork();
+
+               if (child_pid < 0) {
+                       if (errno == EAGAIN) {
+                               iter--;
+                               continue;
+                       }
+                       ksft_exit_fail_msg(
+                               "%s - failed to fork a child process\n",
+                               strerror(errno));
+               }
+
+               if (child_pid == 0) {
+                       /* Child process just sleeps for a min and exits */
+                       sleep(60);
+                       exit(EXIT_SUCCESS);
+               }
+
+               /* Parent kills the child and waits for its death */
+               pidfd = sys_pidfd_open(child_pid, 0);
+               if (pidfd < 0)
+                       ksft_exit_fail_msg("%s - pidfd_open failed\n",
+                                       strerror(errno));
+
+               /* Setup 3 sec alarm - plenty of time */
+               if (signal(SIGALRM, handle_alarm) == SIG_ERR)
+                       ksft_exit_fail_msg("%s - signal failed\n",
+                                       strerror(errno));
+               alarm(3);
+
+               /* Send SIGKILL to the child */
+               if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0))
+                       ksft_exit_fail_msg("%s - pidfd_send_signal failed\n",
+                                       strerror(errno));
+
+               /* Wait for the death notification */
+               fds.fd = pidfd;
+               nevents = poll(&fds, 1, -1);
+
+               /* Check for error conditions */
+               if (nevents < 0)
+                       ksft_exit_fail_msg("%s - poll failed\n",
+                                       strerror(errno));
+
+               if (nevents != 1)
+                       ksft_exit_fail_msg("unexpected poll result: %d\n",
+                                       nevents);
+
+               if (!(fds.revents & POLLIN))
+                       ksft_exit_fail_msg(
+                               "unexpected event type received: 0x%x\n",
+                               fds.revents);
+
+               if (timeout)
+                       ksft_exit_fail_msg(
+                               "death notification wait timeout\n");
+
+               close(pidfd);
+               /* Wait for child to prevent zombies */
+               if (waitpid(child_pid, NULL, 0) < 0)
+                       ksft_exit_fail_msg("%s - waitpid failed\n",
+                                       strerror(errno));
+
+       }
+
+       ksft_test_result_pass("pidfd poll test: pass\n");
+       return ksft_exit_pass();
+}
index b632965..7aff2d3 100644 (file)
 #include "pidfd.h"
 #include "../kselftest.h"
 
-#ifndef __NR_pidfd_send_signal
-#define __NR_pidfd_send_signal -1
-#endif
-
 #define str(s) _str(s)
 #define _str(s) #s
 #define CHILD_THREAD_MIN_WAIT 3 /* seconds */
 
 #define MAX_EVENTS 5
 
-#ifndef CLONE_PIDFD
-#define CLONE_PIDFD 0x00001000
-#endif
-
 static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
 {
        size_t stack_size = 1024;
@@ -47,12 +39,6 @@ static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
 #endif
 }
 
-static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
-                                       unsigned int flags)
-{
-       return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
-}
-
 static int signal_received;
 
 static void set_signal_received_on_sigusr1(int sig)
diff --git a/tools/testing/selftests/pidfd/pidfd_wait.c b/tools/testing/selftests/pidfd/pidfd_wait.c
new file mode 100644 (file)
index 0000000..7079f8e
--- /dev/null
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "pidfd.h"
+#include "../kselftest.h"
+
+#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
+
+static pid_t sys_clone3(struct clone_args *args)
+{
+       return syscall(__NR_clone3, args, sizeof(struct clone_args));
+}
+
+static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
+                     struct rusage *ru)
+{
+       return syscall(__NR_waitid, which, pid, info, options, ru);
+}
+
+static int test_pidfd_wait_simple(void)
+{
+       const char *test_name = "pidfd wait simple";
+       int pidfd = -1, status = 0;
+       pid_t parent_tid = -1;
+       struct clone_args args = {
+               .parent_tid = ptr_to_u64(&parent_tid),
+               .pidfd = ptr_to_u64(&pidfd),
+               .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
+               .exit_signal = SIGCHLD,
+       };
+       int ret;
+       pid_t pid;
+       siginfo_t info = {
+               .si_signo = 0,
+       };
+
+       pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+       if (pidfd < 0)
+               ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n",
+                                  test_name, strerror(errno));
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid == 0)
+               ksft_exit_fail_msg(
+                       "%s test: succeeded to wait on invalid pidfd %s\n",
+                       test_name, strerror(errno));
+       close(pidfd);
+       pidfd = -1;
+
+       pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+       if (pidfd == 0)
+               ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n",
+                                  test_name, strerror(errno));
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid == 0)
+               ksft_exit_fail_msg(
+                       "%s test: succeeded to wait on invalid pidfd %s\n",
+                       test_name, strerror(errno));
+       close(pidfd);
+       pidfd = -1;
+
+       pid = sys_clone3(&args);
+       if (pid < 0)
+               ksft_exit_fail_msg("%s test: failed to create new process %s\n",
+                                  test_name, strerror(errno));
+
+       if (pid == 0)
+               exit(EXIT_SUCCESS);
+
+       pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (pid < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status))
+               ksft_exit_fail_msg(
+                       "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+       close(pidfd);
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_EXITED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ksft_test_result_pass("%s test: Passed\n", test_name);
+       return 0;
+}
+
+static int test_pidfd_wait_states(void)
+{
+       const char *test_name = "pidfd wait states";
+       int pidfd = -1, status = 0;
+       pid_t parent_tid = -1;
+       struct clone_args args = {
+               .parent_tid = ptr_to_u64(&parent_tid),
+               .pidfd = ptr_to_u64(&pidfd),
+               .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
+               .exit_signal = SIGCHLD,
+       };
+       int ret;
+       pid_t pid;
+       siginfo_t info = {
+               .si_signo = 0,
+       };
+
+       pid = sys_clone3(&args);
+       if (pid < 0)
+               ksft_exit_fail_msg("%s test: failed to create new process %s\n",
+                                  test_name, strerror(errno));
+
+       if (pid == 0) {
+               kill(getpid(), SIGSTOP);
+               kill(getpid(), SIGSTOP);
+               exit(EXIT_SUCCESS);
+       }
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_STOPPED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_CONTINUED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_STOPPED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
+       if (ret < 0)
+               ksft_exit_fail_msg(
+                       "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n",
+                       test_name, parent_tid, pidfd, strerror(errno));
+
+       if (info.si_signo != SIGCHLD)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_signo, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_code != CLD_KILLED)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_code, parent_tid, pidfd,
+                       strerror(errno));
+
+       if (info.si_pid != parent_tid)
+               ksft_exit_fail_msg(
+                       "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
+                       test_name, info.si_pid, parent_tid, pidfd,
+                       strerror(errno));
+
+       close(pidfd);
+
+       ksft_test_result_pass("%s test: Passed\n", test_name);
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       ksft_print_header();
+       ksft_set_plan(2);
+
+       test_pidfd_wait_simple();
+       test_pidfd_wait_states();
+
+       return ksft_exit_pass();
+}
index affa7f2..9539cff 100644 (file)
@@ -64,7 +64,7 @@ class SubPlugin(TdcPlugin):
             cmdlist.insert(0, self.args.NAMES['NS'])
             cmdlist.insert(0, 'exec')
             cmdlist.insert(0, 'netns')
-            cmdlist.insert(0, 'ip')
+            cmdlist.insert(0, self.args.NAMES['IP'])
         else:
             pass
 
@@ -78,16 +78,16 @@ class SubPlugin(TdcPlugin):
         return command
 
     def _ports_create(self):
-        cmd = 'ip link add $DEV0 type veth peer name $DEV1'
+        cmd = '$IP link add $DEV0 type veth peer name $DEV1'
         self._exec_cmd('pre', cmd)
-        cmd = 'ip link set $DEV0 up'
+        cmd = '$IP link set $DEV0 up'
         self._exec_cmd('pre', cmd)
         if not self.args.namespace:
-            cmd = 'ip link set $DEV1 up'
+            cmd = '$IP link set $DEV1 up'
             self._exec_cmd('pre', cmd)
 
     def _ports_destroy(self):
-        cmd = 'ip link del $DEV0'
+        cmd = '$IP link del $DEV0'
         self._exec_cmd('post', cmd)
 
     def _ns_create(self):
@@ -97,16 +97,16 @@ class SubPlugin(TdcPlugin):
         '''
         self._ports_create()
         if self.args.namespace:
-            cmd = 'ip netns add {}'.format(self.args.NAMES['NS'])
+            cmd = '$IP netns add {}'.format(self.args.NAMES['NS'])
             self._exec_cmd('pre', cmd)
-            cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS'])
+            cmd = '$IP link set $DEV1 netns {}'.format(self.args.NAMES['NS'])
             self._exec_cmd('pre', cmd)
-            cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS'])
+            cmd = '$IP -n {} link set $DEV1 up'.format(self.args.NAMES['NS'])
             self._exec_cmd('pre', cmd)
             if self.args.device:
-                cmd = 'ip link set $DEV2 netns {}'.format(self.args.NAMES['NS'])
+                cmd = '$IP link set $DEV2 netns {}'.format(self.args.NAMES['NS'])
                 self._exec_cmd('pre', cmd)
-                cmd = 'ip -n {} link set $DEV2 up'.format(self.args.NAMES['NS'])
+                cmd = '$IP -n {} link set $DEV2 up'.format(self.args.NAMES['NS'])
                 self._exec_cmd('pre', cmd)
 
     def _ns_destroy(self):
@@ -115,7 +115,7 @@ class SubPlugin(TdcPlugin):
         devices as well)
         '''
         if self.args.namespace:
-            cmd = 'ip netns delete {}'.format(self.args.NAMES['NS'])
+            cmd = '$IP netns delete {}'.format(self.args.NAMES['NS'])
             self._exec_cmd('post', cmd)
 
     def _exec_cmd(self, stage, command):
index bf5ebf5..9cdd2e3 100644 (file)
         "teardown": [
             "$TC actions flush action skbedit"
         ]
+    },
+    {
+        "id": "630c",
+        "name": "Add batch of 32 skbedit actions with all parameters and cookie",
+        "category": [
+            "actions",
+            "skbedit"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action skbedit",
+                0,
+                1,
+                255
+            ]
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit queue_mapping 2 priority 10 mark 7/0xaabbccdd ptype host inheritdsfield index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action skbedit",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "32",
+        "teardown": [
+            "$TC actions flush action skbedit"
+        ]
+    },
+    {
+        "id": "706d",
+        "name": "Delete batch of 32 skbedit actions with all parameters",
+        "category": [
+            "actions",
+            "skbedit"
+        ],
+        "setup": [
+            [
+                "$TC actions flush action skbedit",
+                0,
+                1,
+                255
+            ],
+            "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit queue_mapping 2 priority 10 mark 7/0xaabbccdd ptype host inheritdsfield index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\""
+        ],
+        "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action skbedit index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions list action skbedit",
+        "matchPattern": "^[ \t]+index [0-9]+ ref",
+        "matchCount": "0",
+        "teardown": []
     }
 ]
index a8a6a0c..6af5c91 100644 (file)
@@ -86,6 +86,12 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
        unsigned int len;
        int mask;
 
+       /* Detect an already handled MMIO return */
+       if (unlikely(!vcpu->mmio_needed))
+               return 0;
+
+       vcpu->mmio_needed = 0;
+
        if (!run->mmio.is_write) {
                len = run->mmio.len;
                if (len > sizeof(unsigned long))
@@ -188,6 +194,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
        run->mmio.is_write      = is_write;
        run->mmio.phys_addr     = fault_ipa;
        run->mmio.len           = len;
+       vcpu->mmio_needed       = 1;
 
        if (!ret) {
                /* We handled the access successfully in the kernel. */
index bdbc297..e621b5d 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cpu.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
@@ -164,12 +165,18 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu0;
                kref_init(&irq->refcount);
-               if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+               switch (dist->vgic_model) {
+               case KVM_DEV_TYPE_ARM_VGIC_V2:
                        irq->targets = 0;
                        irq->group = 0;
-               } else {
+                       break;
+               case KVM_DEV_TYPE_ARM_VGIC_V3:
                        irq->mpidr = 0;
                        irq->group = 1;
+                       break;
+               default:
+                       kfree(dist->spis);
+                       return -EINVAL;
                }
        }
        return 0;
@@ -209,7 +216,6 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
                irq->intid = i;
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu;
-               irq->targets = 1U << vcpu->vcpu_id;
                kref_init(&irq->refcount);
                if (vgic_irq_is_sgi(i)) {
                        /* SGIs */
@@ -219,11 +225,6 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
                        /* PPIs */
                        irq->config = VGIC_CONFIG_LEVEL;
                }
-
-               if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-                       irq->group = 1;
-               else
-                       irq->group = 0;
        }
 
        if (!irqchip_in_kernel(vcpu->kvm))
@@ -286,10 +287,19 @@ int vgic_init(struct kvm *kvm)
 
                for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
                        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
-                       if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+                       switch (dist->vgic_model) {
+                       case KVM_DEV_TYPE_ARM_VGIC_V3:
                                irq->group = 1;
-                       else
+                               irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+                               break;
+                       case KVM_DEV_TYPE_ARM_VGIC_V2:
                                irq->group = 0;
+                               irq->targets = 1U << idx;
+                               break;
+                       default:
+                               ret = -EINVAL;
+                               goto out;
+                       }
                }
        }
 
index 44efc2f..0d09048 100644 (file)
@@ -211,6 +211,12 @@ static void vgic_hw_irq_spending(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
        vgic_irq_set_phys_active(irq, true);
 }
 
+static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
+{
+       return (vgic_irq_is_sgi(irq->intid) &&
+               vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
+}
+
 void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
                              gpa_t addr, unsigned int len,
                              unsigned long val)
@@ -223,6 +229,12 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
        for_each_set_bit(i, &val, len * 8) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
+               /* GICD_ISPENDR0 SGI bits are WI */
+               if (is_vgic_v2_sgi(vcpu, irq)) {
+                       vgic_put_irq(vcpu->kvm, irq);
+                       continue;
+               }
+
                raw_spin_lock_irqsave(&irq->irq_lock, flags);
                if (irq->hw)
                        vgic_hw_irq_spending(vcpu, irq, is_uaccess);
@@ -270,6 +282,12 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
        for_each_set_bit(i, &val, len * 8) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
+               /* GICD_ICPENDR0 SGI bits are WI */
+               if (is_vgic_v2_sgi(vcpu, irq)) {
+                       vgic_put_irq(vcpu->kvm, irq);
+                       continue;
+               }
+
                raw_spin_lock_irqsave(&irq->irq_lock, flags);
 
                if (irq->hw)
index 96aab77..b00aa30 100644 (file)
@@ -184,7 +184,10 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
                if (vgic_irq_is_sgi(irq->intid)) {
                        u32 src = ffs(irq->source);
 
-                       BUG_ON(!src);
+                       if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n",
+                                          irq->intid))
+                               return;
+
                        val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
                        irq->source &= ~(1 << (src - 1));
                        if (irq->source) {
index 0c653a1..a4ad431 100644 (file)
@@ -167,7 +167,10 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
                    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
                        u32 src = ffs(irq->source);
 
-                       BUG_ON(!src);
+                       if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n",
+                                          irq->intid))
+                               return;
+
                        val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
                        irq->source &= ~(1 << (src - 1));
                        if (irq->source) {
index 13d4b38..e7bde65 100644 (file)
@@ -254,6 +254,13 @@ static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
        bool penda, pendb;
        int ret;
 
+       /*
+        * list_sort may call this function with the same element when
+        * the list is fairly long.
+        */
+       if (unlikely(irqa == irqb))
+               return 0;
+
        raw_spin_lock(&irqa->irq_lock);
        raw_spin_lock_nested(&irqb->irq_lock, SINGLE_DEPTH_NESTING);